Sql Server:如何仅在存在时才选择列?

Posted

技术标签:

【中文标题】Sql Server:如何仅在存在时才选择列?【英文标题】:Sql Server: How do you select a column only if it exists? 【发布时间】:2013-05-09 22:06:32 【问题描述】:

我有很多表是相似的数据结构,但在这些方面并不完全相同:

表 1

一个不为空的 int B int 不为空 C int 不为空

表 2

一个不为空的 int B int 不为空

在做一些数据转换后我想要的结果是:

表 3

一个不为空的 int B int 不为空 C int null

还有几个表具有不同但相似的架构,因此我正在编写一个脚本,该脚本将从缺少某些列的各种表中导入表 3。

基于this 问题,我尝试过这样的查询:

SELECT A
      ,B
      ,case 
        when COL_LENGTH('t2', 'C') IS NULL 
        then NULL 
        ELSE C
        end as C
  FROM t2

但它会抛出“无效的列名 C”错误,即使它会选择 null。

是否有另一种方法可以仅在存在时选择列,如果不存在则选择 NULL?

【问题讨论】:

查询 sysobjects/syscolumns 并使用动态 SQL。 【参考方案1】:

此脚本可为任何表结构生成动态 SQL。

查询:

SET NOCOUNT ON

IF OBJECT_ID (N'dbo.Table_1') IS NOT NULL
   DROP TABLE dbo.Table_1

IF OBJECT_ID (N'dbo.Table_2') IS NOT NULL
   DROP TABLE dbo.Table_2

CREATE TABLE dbo.Table_1 (A INT NOT NULL, B INT NOT NULL, C INT NOT NULL)
CREATE TABLE dbo.Table_2 (A INT NOT NULL, B INT NOT NULL)

INSERT INTO dbo.Table_1 (A, B, C)
VALUES (1, 1, 1), (2, 2, 2) 

INSERT INTO dbo.Table_2 (A, B)
VALUES (6, 1), (8, 2) 

DECLARE @SQL NVARCHAR(2000)

;WITH cte AS 
(
    SELECT 
          column_name = '[' + c.name + ']'
        , table_name = '[' + s.name + '].[' + o.name + ']'
    FROM sys.columns c WITH (NOLOCK)
    JOIN sys.objects o WITH (NOLOCK) ON c.[object_id] = o.[object_id]
    JOIN sys.schemas s WITH (NOLOCK) ON o.[schema_id] = s.[schema_id]
    WHERE o.name IN ('Table_1', 'Table_2')
        AND s.name = 'dbo'
        AND o.[type] = 'U'  
), cols AS 
(
    SELECT DISTINCT column_name 
    FROM cte    
), tbl AS 
(
    SELECT DISTINCT table_name
    FROM cte
), rs AS 
(
    SELECT 
          tbl.table_name
        , column_name = ISNULL(cte.column_name, cols.column_name + ' = NULL')
    FROM cols
    CROSS JOIN tbl
    LEFT JOIN cte ON cols.column_name = cte.column_name AND cte.table_name = tbl.table_name
), rs2 AS (
    SELECT uni = ' UNION ALL' + CHAR(13) + 'SELECT ' + STUFF((
        SELECT ', ' + rs.column_name
        FROM rs
        WHERE tbl.table_name = rs.table_name
        GROUP BY rs.column_name
        ORDER BY rs.column_name
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + 
        ' FROM ' + table_name
    FROM tbl
) 
SELECT @SQL = 'SELECT 
' + STUFF((
    SELECT CHAR(13) + ', ' + cols.column_name
    FROM cols
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ' ')
 + ' 
FROM 
(' + STUFF((
    SELECT CHAR(10) + uni
    FROM rs2
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 11, '') + CHAR(13) + 
    ') t'

PRINT @SQL

EXECUTE sys.sp_executesql @SQL

输出:

SELECT 
      [A]
    , [B]
    , [C] 
FROM 
(
    SELECT [A], [B], [C] FROM [dbo].[Table_1]
     UNION ALL
    SELECT [A], [B], [C] = NULL FROM [dbo].[Table_2]
) t

结果:

A           B           C
----------- ----------- -----------
1           1           1
2           2           2
6           1           NULL
8           2           NULL

【讨论】:

相关问题:***.com/questions/16474398/… 翻译的时候看drop table语句哈哈【参考方案2】:

你能用UNION吗?

select A, B, C FROM Table1
UNION
Select A, B, null FROM Table2

【讨论】:

这是一种可能性,但这意味着我必须对源表中的所有不同模式进行硬编码和维护,而不仅仅是选择目标模式。

以上是关于Sql Server:如何仅在存在时才选择列?的主要内容,如果未能解决你的问题,请参考以下文章

仅在列存在时才提供数据框列表

仅当表中不存在该值时才更新 SQL 列

如何在 SQL Server 视图中选择值(如果存在)或其他值(如果不在 SQL Server 视图中)

Laravel:如何仅在模型关系存在时才查询模型关系

SQL如何仅在组遵循某些规则时才找到许多组总和的平均值

SQL Plus如何仅在同一帐户没有两个不同结果时才显示行