Sql 在投影级别中应用条件

Sql 在投影级别中应用条件,sql,tsql,plsql,Sql,Tsql,Plsql,是否有一种简单的方法来应用投影级别中的条件?我的意思是,在一系列字段列中,我们如何仅选择具有特定条件的字段 例如: 假设我们有一个查询,结果如下: Id Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9 Col10 Col11 - ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --

是否有一种简单的方法来应用投影级别中的条件?我的意思是,在一系列字段列中,我们如何仅选择具有特定条件的字段

例如:

假设我们有一个查询,结果如下:

Id  Col1    Col2    Col3    Col4    Col5    Col6    Col7    Col8    Col9    Col10   Col11
-   ----    ----    ----    ----    ----    ----    ----    ----    ----    ----    ----
1   V1_1    NULL    NULL    V4_1    NULL    NULL    NULL    NULL    NULL    V10_1   NULL
2   V1_2    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    V10_2   NULL
3   V1_3    NULL    NULL    V4_3    NULL    NULL    NULL    NULL    NULL    V10_3   NULL
我们如何只选择包含非空值的字段,而不知道其中哪些字段包含非空值?因此,结果将是:

Id  Col1    Col4    Col10
-   ----    ----    ----
1   V1_1    V4_1    V10_1
2   V1_2    NULL    V10_2
3   V1_3    V4_3    V10_3
通常我用硬编码来执行这些查询,我可以在MsSQL服务器中查询sys.all_obejcts、sys.all_列,在Oracle中查询所有_tab_列、所有_表等。并在其中使用none、一个或多个游标、case语句、pivot、多个ifs或动态sql

例如:对于在T-SQL中包含上述数据的表,我可以执行以下操作:

DECLARE @sql VARCHAR(500)
SET @sql='SELECT Id,'
IF EXISTS (SELECT Col1 FROM tblTEST WHERE Col1 IS NOT NULL)  SET @sql=@sql+'Col1,'
/* 9 other IF statements here */
IF EXISTS (SELECT Col11 FROM tblTEST WHERE Col11 IS NOT NULL)  SET @sql=@sql+'Col11,'
SET @sql=SUBSTRING(@sql,1,LEN(@sql)-1)+' FROM tblTEST'
EXEC(@sql)
但是,正如您所看到的,这种想法并不常见,而且为这些场景编写这样的代码有点困难

您知道一种简单且更好的方法或模式来处理此类查询吗

RDBMS并不重要,任何RDBMS的好解决方案都非常有用


请注意,我希望答案在总体上是一个好主意,不仅仅是对于我提到的示例。

这是一个T-SQL解决方案。您只需将@TargetTable更改为所需的表。希望这有帮助!我评论了我的代码解释了一切,但是如果你有任何问题,请告诉我

 IF OBJECT_ID('myTable') IS NOT NULL
    DROP TABLE dbo.myTable;

CREATE TABLE myTable
(
    ID INT IDENTITY(1,1),
    Col1 VARCHAR(25),
    Col2 VARCHAR(25),
    Col3 VARCHAR(25)
)


INSERT INTO dbo.myTable(Col1,Col2,Col3)
    VALUES  ('v1_1',NULL,NULL),
            ('v1_2','v2_2',NULL),
            ('v1_3',NULL,NULL);


/* Now that I've set up the problem, here's for the actual code*/
--Set your desired table
DECLARE @TargetTable VARCHAR(100) = 'myTable'

--If this global temp table exists, drop it
IF OBJECT_ID('##tempTable') IS NOT NULL
    EXEC('DROP TABLE ##tempTable');

--This is going to take one character and cast it to NCHAR(1)
    --If there are no characters, it will simply return NULL
DECLARE @AllColumns VARCHAR(MAX);

SELECT @AllColumns = COALESCE(@AllColumns + ',','') + 'CAST(LEFT(' + QUOTENAME(COLUMN_NAME) + ',1) AS NCHAR(1)) AS ' + QUOTENAME(COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS A
WHERE TABLE_NAME = @TargetTable

/*Load your char results into a global temp table*/
EXEC('SELECT ' + @AllColumns + ' INTO ##tempTable FROM ' + @TargetTable);

/*Here's where the fun beings*/

/*  @DesiredCol holds the name of columns that are not null.
    UNPIVOT the data.
    Where clause gets rid of columns with only NULL values.
    Group by only allows distinct columns.
    You the select from your ORIGINAL table, not my funky nchar(1) global temp table.
*/

EXEC(

    'DECLARE @DesiredCol VARCHAR(MAX);
    SELECT @DesiredCol = COALESCE(@DesiredCol + '','','''') + QUOTENAME(col)
    FROM ##temptable 
    UNPIVOT
    (
    val FOR col IN ([ID],[Col1],[Col2],[Col3])
    ) pvt
    WHERE pvt.val IS NOT NULL
    GROUP BY col

    EXEC (''SELECT '' + @DesiredCol + '' FROM ##' + @TargetTable + ''')'
    )
--Cleanup
IF OBJECT_ID('##tempTable') IS NOT NULL
    EXEC('DROP TABLE ##tempTable');

这通常是一个表示逻辑问题。但是,如果需要一组动态列,则必须使用动态sql。没有一种独立于数据库的方法来实现这一点,每种口味都是不同的……是的,据我所知,你是对的。我想可能有人有更好的想法或信息,或者bean有过很好的解决方案,这就是我问这个问题的原因。