这是表1.表2数据如下:
通过加入上述数据,我想查询如下。外部ID应该是特定的cvid和cid。例如,
1001*98564*2*2*5*1
1002*98564*5*6*2*1
1003*98565*2*2*2*2
1004*98566*1*6*5*2
以下是我转动表1数据的查询:
select cvid,cid, sum(case when question_text = 'text1' then extid else 0 end) as [a],
sum(case when question_text = 'text2' then extid else 0 end) as [b],
sum(case when question_text = 'text3' then extid else 0 end) as [c],
sum(case when question_text = 'text4' then extid else 0 end) as [d]
from #sampletab
但无法超越。任何建议?
PS:第二张表中的数据和时间没用!此外,我不允许硬编码任何ID。但是我已经对问题文本进行了硬编码,因为我没有其他选择。
答案 0 :(得分:0)
我们将从这里开始:
SELECT t2.cvid, t2.cid,
MAX(CASE WHEN t1.qid = 11 THEN t1.extid ELSE 0 END) A,
MAX(CASE WHEN t1.qid = 21 THEN t1.extid ELSE 0 END) B,
MAX(CASE WHEN t1.qid = 31 THEN t1.extid ELSE 0 END) C,
MAX(CASE WHEN t1.qid = 41 THEN t1.extid ELSE 0 END) D
FROM Table2 t2
INNER JOIN Table1 t1 ON t1.cvid = t2.cvid and t1.cid = t2.cid
GROUP BY t2.cvid, t2.cid
这会产生问题中请求的结果,尽管使用硬编码的qid值。可以使用条件聚合简化它,如下所示:
qid
这也符合您在问题中尝试做的更少的代码和可能更好的性能,但请记住第一个选项;我们将进一步调整它。
此外,我不允许硬编码任何ID。
为什么不呢? SQL语言的一个怪癖是必须能够在编译时知道语言的结果集中列的数量和类型。如果您可以拥有任意数量的未知PIVOT
值,那么您将别无选择,只能通过动态SQL分两步执行此操作。即使使用qid
关键字,也必须声明结果集的列。
如果确实想要避免使用quest
/ question_text
/ WITH ID_Map As (
SELECT row_number() over (ORDER by qid) as RowKey, qid
FROM Table1
GROUP BY qid
)
SELECT t2.cvid, t2.cid, t1a.extid, t1b.extid, t1c.extid, t1d.extid
FROM Table2 t2
INNER JOIN ID_Map m1 ON m1.RowKey = 1
INNER JOIN Table1 t1a ON t1a.cvid = t2.cvid and t1a.cid = t2.cid
AND t1a.qid = m1.qid
INNER JOIN ID_Map m2 ON m2.RowKey = 2
INNER JOIN Table1 t1b ON t1b.cvit1bd = t2.cvid and t1b.cid = t2.cid
AND t1b.qid = m2.qid
INNER JOIN ID_Map m3 ON m3.RowKey = 3
INNER JOIN Table1 t1c ON t1c.cvid = t2.cvid and t1c.cid = t2.cid
AND t1c.qid = m3.qid
INNER JOIN ID_Map m4 ON m4.RowKey = 4
INNER JOIN Table1 t1d ON t1d.cvid = t2.cvid and t1d.cid = t2.cid
AND t1d.qid = m4.qid
值,但仍知道列数,我们可以回到我的答案的第一部分,并使其适应使用这样的地图(提示:它更慢,仍然要求ID是离散的和一致的):
qid
这里唯一的优点是您不需要确切知道cvid
值是什么。你只需知道其中有四个,并且它们被一致地使用。
我们可以通过在地图中加入cid
和WITH ID_Map As (
SELECT cvid, cid, qid, row_number() over (PARTITION BY cvid, cid ORDER by qid) as RowKey
FROM Table1
)
SELECT t2.cvid, t2.cid, t1a.extid, t1b.extid, t1c.extid, t1d.extid
FROM Table2 t2
INNER JOIN ID_Map m1 ON m1.cvid = t2.cvid and m1.cid = t2.cid
AND m1.RowKey = 1
INNER JOIN Table1 t1a ON t1a.cvid = t2.cvid and t1a.cid = t2.cid
AND t1a.qid = m1.qid
INNER JOIN ID_Map m2 ON m2.cvid = t2.cvid and m2.cid = t2.cid
AND m2.RowKey = 2
INNER JOIN Table1 t1b ON t1b.cvit1bd = t2.cvid and t1b.cid = t2.cid
AND t1b.qid = m2.qid
INNER JOIN ID_Map m3 ON m3.cvid = t2.cvid and m3.cid = t2.cid
AND m3.RowKey = 3
INNER JOIN Table1 t1c ON t1c.cvid = t2.cvid and t1c.cid = t2.cid
AND t1c.qid = m3.qid
INNER JOIN ID_Map m4 ON m4.cvid = t2.cvid and m4.cid = t2.cid
AND m4.RowKey = 4
INNER JOIN Table1 t1d ON t1d.cvid = t2.cvid and t1d.cid = t2.cid
AND t1d.qid = m4.qid
值来做得更好一点:
LEFT JOIN
现在不再需要在问题之间一致地使用代码了。知道代码的问题就足够了......虽然这仍然是一项艰难的要求。请记住,SQL语言要求必须具有一组已知的结果列。您可以在一些地方使用INNER JOIN
而不是NULL
来进一步改善这一点,这种方式可能会为结果中的某些列提供{{1}}值,而不是删除记录完全。我把它留作练习。
作为最后一点,传统观点是,在从数据库中检索客户端程序之后,您最好能够将这些数据转移到客户端程序上。