传递多个ID以返回case语句中的列

时间:2019-04-23 08:25:59

标签: sql sql-server case dynamic-sql

我正在使用一些动态SQL根据订阅类型返回一些列。我遇到的问题是多种订阅类型。虽然我可以胜任处理1种订阅类型。我不知道如何处理2种订阅类型。我总共有8种不同的类型。

例如:

DECLARE @subType tinyint = 2

DECLARE @Id varchar(4) = 'U01'
DECLARE @SQLProjectDetails nvarchar(MAX)

SET @SQLProjectDetails = N'SELECT ' +
       STUFF(
            -- General Information 

            CASE WHEN @subType IN (1,2,3,4) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.Id' ELSE N'' END + 
            CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.Name' ELSE N'' END + 
            CASE WHEN @subType IN (5,6,8) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'       wf1.OtherNames' ELSE N'' END +
            CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.CountryName' ELSE N'' END +
             , 1, 10,N'') + NCHAR(13) + NCHAR(10) +
            N'FROM Table wf1where (wf1.Id= @p)';

EXEC sp_executesql @SQLProjectDetails,  N'@p varchar(4)', @p = @Id; 

但是,如果我的订阅类型为2和5,该怎么办?

所以othernames列也将被返回?我遇到的主要问题是8种不同的订阅类型。虽然我可以尝试解决所有可能的情况,但我还是更愿意动态地执行此操作(主要是因为有40000种不同的变化)。

1 个答案:

答案 0 :(得分:0)

如果您有一个像这样的ColLookup表:

myTileLayer.addTo(map)

然后,像这样的SQL将为您提供应拉出的列名:

SubType, ColumnName
1,wf1.Id
2,wf1.Id
3,wf1.Id
4,wf1.Id
1,wf1.Name
2,wf1.Name
5,wf1.OtherNames
6,wf1.OtherNames
8,wf1.OtherNames
1,wf1.CountryName
2,wf1.CountryName

如果o.id 1234的子类型为1,则此SQL将返回

SELECT 
  STRING_AGG(l.ColumnName, ',') as ColList
FROM
  otherTable o
  INNER JOIN
  ColLookup l on o.subtype = l.subtype
WHERE
  o.id = 1234

如果o.id X的子类型为3,则此SQL将返回

'wf1.Id,1,wf1.Name,wf1.CountryName'

使其具有完整的SQL可能类似于:

'wf1.Id'

您可以将其分配给变量并执行它

如果您的SQLS是2017之前的版本,并且没有STRING_AGG,请使用类似的方法将多行连接到单个字符串中,例如STUFF / FOR XML PATH。如果需要定义顺序,请在查询表中添加一个顺序列(STRING_AGG具有WITHIN GROUP ORDER BY选项,我敢肯定其他方法也具有更改连续字符串顺序的选项)

尽管如此,我还是会在C#中做到这一点。我将运行选择所有内容的主查询,然后运行:

SELECT 
  CONCAT('SELECT ', STRING_AGG(l.ColumnName, ','), ' FROM blah')  as sq
FROM
  otherTable o
  INNER JOIN
  ColLookup l on o.subtype = l.subtype
WHERE
  o.id = 1234

我将其放入字典/哈希集中(使用linq伪代码,但是您需要):

SELECT ColName FROM ColLookup WHERE SubType in (1,5)

然后我将主查询放入数据表中,并删除不需要的列:

//this is a union - anything 1 can see or 5 can see
var dict = dbcontext.Wf1Table.Where(r => r == 1 || r == 5).Distinct().ToDictionary(r => r.ColumnName, r => r.ColumnName)

//this is an intersect - anything common to 1 and 5 only
var dict = dbcontext.Wf1Table.Where(r => r == 1).Intersect(dbcontext.Wf1Table.Where(r => r == 5)).ToDictionary(r => r.ColumnName, r => r.ColumnName)

//this is if you downloaded the columns into a datatable
//SELECT DISTINCT colname FROM t WHERE subtype IN (1,5) --union
//SELECT colname FROM t WHERE subtype IN (1,5) GROUP BY colname HAVING COUNT(*) = 2 --intersection
var dict = new Dictionary(string, string);
foreach(var ro in colnamedatatable)
  dict[ro.ColName] = null;

如果您要坚持使用SQL进行操作,则会产生交叉:

for(int c = datatable.Columns.Length -1; c >= 0; c--) //gobackwards
  if(!dict.ContainsKey(datatable.Columns[c].ColumnName))
    datatable.Columns.RemoveAt(c);

某事需要知道给定ID的子类型个数;数据库知道,但是很难指导您,因为您还没有说过数据的存储方式。如果正确(多个ID记录/中间人表),则此查询有效。如果是“逗号分隔的列表”,那么(嗯)它需要解析为两行