动态创建多个表之间的JOIN查询

时间:2015-12-23 10:37:18

标签: sql sql-server-2008

CREATE TABLE t1 (
id    int,
name  varchar(50),

PRIMARY KEY (id)
);

insert into t1 (id,name) values(1,'t1.1')
insert into t1 (id,name) values(2,'t1.2')
insert into t1 (id,name) values(3,'t1.3')

CREATE TABLE t2 (
  id    int,
  name  varchar(50),

  PRIMARY KEY (id),
  CONSTRAINT fk_t1_t2 FOREIGN KEY (Id) REFERENCES t1(Id)
);

insert into t2 (id,name) values(1,'t2.1')
insert into t2 (id,name) values(2,'t2.2')
insert into t2 (id,name) values(3,'t2.3')



-- SQL created manualy:
select * from t1
join t2 on t2.id = t1.id


drop table t2
drop table t1

这是一个非常简单的例子。想想一个包含大量外键引用的巨型数据库结构!

手动定义所有连接条件是一项艰巨的任务!

我想动态创建这个SQL语句!

外部引用已在数据库中定义,但在哪里?

脚本应该这样做:

  select 
    t1.id,
    t1.name,
    t2.id,
    it2.name
  from t1
  join t2 on t2.id = t1.id 

有人已经解决了这个问题吗?

附录:脚本的参数是第一个Tablename和最后一个Tablename。这两个表应与所有相关的表间或参考表连接在一起。

2 个答案:

答案 0 :(得分:3)

这样可以解决问题,但我不建议这样做。

问题:更频繁地引用同一个表(别名),加入类型(内部,左侧,......),所选列列表......

DECLARE @table AS VARCHAR(100)='YouTableName';

WITH AllColumns AS
(
    SELECT pObj.name AS ParentTable  
          ,pCol.COLUMN_NAME AS ParentColumn
          ,fkObj.name AS ReferecedTable 
          ,fkCol.COLUMN_NAME AS ReferencedColumn

    FROM sys.foreign_key_columns AS fkc 
    INNER JOIN sys.objects AS pObj ON pObj.object_id=fkc.parent_object_id
    INNER JOIN INFORMATION_SCHEMA.COLUMNS AS pCol ON pCol.TABLE_NAME=pObj.name AND pCol.ORDINAL_POSITION=fkc.parent_column_id 
    INNER JOIN sys.objects AS fkObj ON fkObj.object_id=fkc.referenced_object_id
    INNER JOIN INFORMATION_SCHEMA.COLUMNS AS fkCol ON fkCol.TABLE_NAME=fkObj.name AND fkCol.ORDINAL_POSITION=fkc.referenced_column_id 
    WHERE fkc.constraint_object_id IN 
    (
        SELECT object_id FROM sys.objects AS o
        WHERE o.name IN
        (
            SELECT tc.CONSTRAINT_NAME
            FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc
            WHERE tc.CONSTRAINT_TYPE='FOREIGN KEY'
              AND tc.TABLE_NAME=@table
        )
    )
)
SELECT 'SELECT *
        FROM ' + @table +
        (
            SELECT ' INNER JOIN ' + ac.ReferecedTable + ' ON ' + ac.ParentTable + '.' + ac.ParentColumn + '=' + ac.ReferecedTable + '.' + ac.ReferencedColumn + CHAR(10) 
            FROM AllColumns AS ac
            FOR XML PATH('')
        )

答案 1 :(得分:0)

Shnugo中的精彩脚本。但这有一些缺点:

  1. 它不适用于自定义方案-仅适用于默认表 dbo模式
  2. 它不适用于带有Unicode符号或空格的表
  3. 它没有PRINT带有 nice 格式设置选项的语句

我改进了此脚本来解决此问题:

    /*
    <documentation>
      <summary>Create JOIN query between multiple tables dynamically.</summary>
      <returns>SELECT statement from input table with INNER JOINS for all tables having foreign consttraints with input table.</returns>
      <issues>Does not properly generate alias for case with multiply foreign keys for one table</issues>
      <author>Konstantin Taranov</author>
      <created>2019-04-22</created>
      <modified>2019-04-23 by Konstantin Taranov</modified>
      <version>1.1</version>
      <sourceLink>https://github.com/ktaranov/sqlserver-kit/blob/master/Scripts/Create_JOIN_Query_Between_Multiple_Tables_Dynamically.sql</sourceLink>
    </documentation>
    */

    DECLARE @schemaName    AS sysname       = N'dbo';
    DECLARE @tableName     AS sysname       = N'TableName';
    DECLARE @tableFullName AS nvarchar(256) = QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName)
    DECLARE @crlf          AS varchar(10)   = CHAR(10);
    DECLARE @tsql          AS nvarchar(max);

    IF LEFT(@tableName, 1) = N'[' OR LEFT(@schemaName, 1) = N'['
    THROW 50001, 'Please do not use quotes in Table or Schema names! In the script it is alredy done with QUOTENAME function.', 1;

    IF OBJECT_ID(@tableFullName) IS NULL
    THROW 50002, 'Table is not exist in database. Please check @schemaName and @tableName variables.', 1;


    WITH AllColumns
         AS (SELECT
                    pObj.name                    AS ParentTable
                   ,pCol.COLUMN_NAME             AS ParentColumn
                   ,SCHEMA_NAME(fkObj.schema_id) AS ReferecedTableSchema
                   ,fkObj.name                   AS ReferecedTable
                   ,fkCol.COLUMN_NAME            AS ReferencedColumn
             FROM sys.foreign_key_columns AS fkc
                  INNER JOIN sys.objects  AS pObj ON pObj.object_id = fkc.parent_object_id
                  INNER JOIN INFORMATION_SCHEMA.COLUMNS AS pCol ON pCol.TABLE_NAME = pObj.name
                                                                   AND pCol.ORDINAL_POSITION = fkc.parent_column_id
                  INNER JOIN sys.objects AS fkObj ON fkObj.object_id = fkc.referenced_object_id
                  INNER JOIN INFORMATION_SCHEMA.COLUMNS AS fkCol ON fkCol.TABLE_NAME = fkObj.name
                                                                    AND fkCol.ORDINAL_POSITION = fkc.referenced_column_id
             WHERE fkc.constraint_object_id IN
             (
                 SELECT
                        object_id
                 FROM sys.objects AS o
                 WHERE o.name IN
                 (
                     SELECT
                            tc.CONSTRAINT_NAME AS CONSTRAINT_NAME
                     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc
                     WHERE tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
                       AND tc.TABLE_NAME   = @tableName
                       AND tc.TABLE_SCHEMA = @schemaName
                 )
             ))
         SELECT 
                @tsql = 
               N'SELECT TOP(100) ' + QUOTENAME(@tableName) + N'.*' + @crlf +
               N'FROM ' + @tableFullName +
         ISNULL(
         (
             SELECT
                    @crlf +  N'INNER JOIN ' + QUOTENAME(ac.ReferecedTableSchema) + N'.' + QUOTENAME(ac.ReferecedTable) + N' ON' + @crlf +
                    N'           ' + QUOTENAME(ac.ParentTable) + N'.' + QUOTENAME(ac.ParentColumn) + ' = ' +
                    QUOTENAME(ac.ReferecedTable) + '.' + QUOTENAME(ac.ReferencedColumn)
             FROM AllColumns AS ac FOR
             XML PATH('')
         ), N'') + N';';

    IF @tsql IS NULL
    PRINT('@tsql is NULL - something went wrong!');
    ELSE
    PRINT(@tsql);