автоматически создает представления для кучи таблиц

Я ищу способ автоматического создания представления 1: 1 для каждой таблицы для группы таблиц. Поскольку существует множество таблиц, для которых мне нужен вид, было бы трудоемким создавать их вручную.

Идеальный сценарий - это запрос, создающий запросы create view для каждой таблицы, заданной сразу.

0
nl ja de
что ты уже испробовал? Вы можете запросить sys.tables и sys.columns , чтобы получить имена тебе нужно; это помогает?
добавлено автор Pondlife, источник
Что означает «элегантный»? Независимо от того, какое решение вы выберете, вам нужно будет получить имена таблиц и столбцов и создать инструкцию CREATE VIEW . Итак, единственный вопрос: делаете ли вы это в TSQL или используете внешний код (возможно, используя SMO)?
добавлено автор Pondlife, источник
Что означает «элегантный»? Независимо от того, какое решение вы выберете, вам нужно будет получить имена таблиц и столбцов и создать инструкцию CREATE VIEW . Итак, единственный вопрос: делаете ли вы это в TSQL или используете внешний код (возможно, используя SMO)?
добавлено автор Pondlife, источник
да. Я просмотрел этот созданный динамический sql для создания представлений. надеялся на более «элегантное» решение!
добавлено автор Nico, источник
да. Я просмотрел этот созданный динамический sql для создания представлений. надеялся на более «элегантное» решение!
добавлено автор Nico, источник

4 ответы

Это должно сделать трюк для текущей базы данных. Это все еще динамический SQL, но ... Обратите внимание, что он не проверяет, существуют ли представления. Вы можете добавить предложение WHERE в запрос курсора для ограничения таблиц - WHERE t.name = '...' или WHERE t.name IN (' ... '' .... ') .

DECLARE @TableName sysname
DECLARE @ColumnCount INT
DECLARE @ColumnID INT
DECLARE @SelectColumn NVARCHAR(500)
DECLARE @sql NVARCHAR(max) = ''

DECLARE QUERYINFO CURSOR FOR
    SELECT
        t.name AS TableName,
        ccount.ColumnCount,
        c.column_id AS ColumnID,
        CASE WHEN c.column_id <> ccount.ColumnCount
                THEN c.name + ', '
             ELSE c.name
             END AS SelectColumn
    FROM sys.tables t
    INNER JOIN sys.columns c ON t.object_id=c.object_id
    INNER JOIN (
        SELECT object_id,COUNT(*) AS ColumnCount
        FROM sys.columns
        GROUP BY object_id
    ) ccount ON t.object_id = ccount.object_id
    ORDER BY t.Name,c.column_id

OPEN QUERYINFO
FETCH NEXT FROM QUERYINFO INTO @TableName,@ColumnCount,@ColumnID,@SelectColumn
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @ColumnID = 1
    BEGIN
        SET @sql = 'CREATE VIEW v_' + @TableName + ' AS SELECT ' + @SelectColumn
    END
    ELSE
    BEGIN
        SET @sql = @sql + @SelectColumn
    END  

    IF @ColumnID = @ColumnCount
    BEGIN
        SET @sql = @sql + ' FROM ' + @TableName
        EXEC sys.sp_executesql @sql
        SET @sql = ''
    END 

    FETCH NEXT FROM QUERYINFO INTO @TableName,@ColumnCount,@ColumnID,@SelectColumn
END

CLOSE QUERYINFO
DEALLOCATE QUERYINFO
1
добавлено
Просто предостережение - предложение IF \ @ColumnID = \ @ColumnCount может работать не так, как ожидалось, потому что ColumnID могут быть не последовательными, то есть после удаления столбца (кроме последнего) идентификаторы не перенумеровываются.
добавлено автор Rashack, источник

Это должно сделать трюк для текущей базы данных. Это все еще динамический SQL, но ... Обратите внимание, что он не проверяет, существуют ли представления. Вы можете добавить предложение WHERE в запрос курсора для ограничения таблиц - WHERE t.name = '...' или WHERE t.name IN (' ... '' .... ') .

DECLARE @TableName sysname
DECLARE @ColumnCount INT
DECLARE @ColumnID INT
DECLARE @SelectColumn NVARCHAR(500)
DECLARE @sql NVARCHAR(max) = ''

DECLARE QUERYINFO CURSOR FOR
    SELECT
        t.name AS TableName,
        ccount.ColumnCount,
        c.column_id AS ColumnID,
        CASE WHEN c.column_id <> ccount.ColumnCount
                THEN c.name + ', '
             ELSE c.name
             END AS SelectColumn
    FROM sys.tables t
    INNER JOIN sys.columns c ON t.object_id=c.object_id
    INNER JOIN (
        SELECT object_id,COUNT(*) AS ColumnCount
        FROM sys.columns
        GROUP BY object_id
    ) ccount ON t.object_id = ccount.object_id
    ORDER BY t.Name,c.column_id

OPEN QUERYINFO
FETCH NEXT FROM QUERYINFO INTO @TableName,@ColumnCount,@ColumnID,@SelectColumn
WHILE @@FETCH_STATUS = 0
BEGIN
    IF @ColumnID = 1
    BEGIN
        SET @sql = 'CREATE VIEW v_' + @TableName + ' AS SELECT ' + @SelectColumn
    END
    ELSE
    BEGIN
        SET @sql = @sql + @SelectColumn
    END  

    IF @ColumnID = @ColumnCount
    BEGIN
        SET @sql = @sql + ' FROM ' + @TableName
        EXEC sys.sp_executesql @sql
        SET @sql = ''
    END 

    FETCH NEXT FROM QUERYINFO INTO @TableName,@ColumnCount,@ColumnID,@SelectColumn
END

CLOSE QUERYINFO
DEALLOCATE QUERYINFO
1
добавлено
Просто предостережение - предложение IF \ @ColumnID = \ @ColumnCount может работать не так, как ожидалось, потому что ColumnID могут быть не последовательными, то есть после удаления столбца (кроме последнего) идентификаторы не перенумеровываются.
добавлено автор Rashack, источник

Я знаю, что это немного устарело, но вы можете использовать временную таблицу с рекурсивным CTE для объединения столбцов из sys.columns и sys.tables, а затем построить представление без использования процедуры или курсора. Вот пример. Этот только выбирает один object_id, но вы можете запустить его для всех таблиц в вашем db. Единственная проблема может возникнуть, если у вас есть таблица размером более 100 столбцов. Я думаю, что глубина по умолчанию CTE составляет 100 рекурсивных объединений.

SELECT t.name AS TableName
        , ccount.ROW_COUNT
        , c.column_id AS ROW_RANK
        , c.name as COL

INTO #VT_TEMP

FROM sys.tables t  INNER JOIN sys.columns c 
ON t.object_id=c.object_id

INNER JOIN (  SELECT  object_id
                    , COUNT(*) AS ROW_COUNT
               FROM sys.columns
               GROUP BY object_id
    ) ccount 
ON t.object_id = ccount.object_id
WHERE t.OBJECT_ID = 245575913
ORDER BY t.Name, c.COLUMN_ID
;



WITH MYVIEW_CTE  ( T_NAME, R_COUNT, R_RANK, TXT )

AS 
  (
    SELECT TABLENAME
         , ROW_COUNT
         , ROW_RANK
         , CAST(COL AS VARCHAR(MAX))

    FROM #VT_TEMP 
    WHERE ROW_RANK = 1

    UNION ALL

    SELECT  V.TABLENAME
          , V.ROW_COUNT 
          , V.ROW_RANK
          , CAST(TXT  + ', ' +  V.COL AS VARCHAR(MAX)) 


    FROM #VT_TEMP V INNER JOIN MYVIEW_CTE C
    ON  V.TABLENAME = T_NAME
    AND V.ROW_RANK = R_RANK + 1
 )  

 SELECT CC.T_NAME
        ,CC.TXT
        , 'CREATE VIEW V_' + CC.T_NAME + ' AS SELECT ' + CC.TXT + ' FROM dbo.' + CC.T_NAME + ' ;' as DDL_View
 FROM MYVIEW_CTE CC INNER JOIN (

 SELECT T_NAME, MAX(R_RANK) AS MX_CNT
 FROM MYVIEW_CTE C
 GROUP BY T_NAME
 ) SC
 ON CC.T_NAME = SC.T_NAME
 AND CC.R_RANK = SC.MX_CNT
0
добавлено

Я знаю, что это немного устарело, но вы можете использовать временную таблицу с рекурсивным CTE для объединения столбцов из sys.columns и sys.tables, а затем построить представление без использования процедуры или курсора. Вот пример. Этот только выбирает один object_id, но вы можете запустить его для всех таблиц в вашем db. Единственная проблема может возникнуть, если у вас есть таблица размером более 100 столбцов. Я думаю, что глубина по умолчанию CTE составляет 100 рекурсивных объединений.

SELECT t.name AS TableName
        , ccount.ROW_COUNT
        , c.column_id AS ROW_RANK
        , c.name as COL

INTO #VT_TEMP

FROM sys.tables t  INNER JOIN sys.columns c 
ON t.object_id=c.object_id

INNER JOIN (  SELECT  object_id
                    , COUNT(*) AS ROW_COUNT
               FROM sys.columns
               GROUP BY object_id
    ) ccount 
ON t.object_id = ccount.object_id
WHERE t.OBJECT_ID = 245575913
ORDER BY t.Name, c.COLUMN_ID
;



WITH MYVIEW_CTE  ( T_NAME, R_COUNT, R_RANK, TXT )

AS 
  (
    SELECT TABLENAME
         , ROW_COUNT
         , ROW_RANK
         , CAST(COL AS VARCHAR(MAX))

    FROM #VT_TEMP 
    WHERE ROW_RANK = 1

    UNION ALL

    SELECT  V.TABLENAME
          , V.ROW_COUNT 
          , V.ROW_RANK
          , CAST(TXT  + ', ' +  V.COL AS VARCHAR(MAX)) 


    FROM #VT_TEMP V INNER JOIN MYVIEW_CTE C
    ON  V.TABLENAME = T_NAME
    AND V.ROW_RANK = R_RANK + 1
 )  

 SELECT CC.T_NAME
        ,CC.TXT
        , 'CREATE VIEW V_' + CC.T_NAME + ' AS SELECT ' + CC.TXT + ' FROM dbo.' + CC.T_NAME + ' ;' as DDL_View
 FROM MYVIEW_CTE CC INNER JOIN (

 SELECT T_NAME, MAX(R_RANK) AS MX_CNT
 FROM MYVIEW_CTE C
 GROUP BY T_NAME
 ) SC
 ON CC.T_NAME = SC.T_NAME
 AND CC.R_RANK = SC.MX_CNT
0
добавлено
SqlCom.ru - Стиль жизни SQL
SqlCom.ru - Стиль жизни SQL
908 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только MS SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz). Предложения в @sql_ninja

SQL_Ninja
SQL_Ninja
340 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz)