我正在使用一些动态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种不同的变化)。
答案 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记录/中间人表),则此查询有效。如果是“逗号分隔的列表”,那么(嗯)它需要解析为两行