SQL查询:按Ques_ID拆分Ans_Tex到不同列并筛选指定数据
解决SQL行转列+多条件筛选问题(适合初学者)
嘿,作为SQL初学者遇到这种“同一ID重复出现,还要同时满足不同行条件”的问题太正常啦!我来一步步帮你搞定,不仅能把不同ques_id的ans_text放到不同列,还能精准筛选出符合要求的记录~
问题核心分析
你之前的查询里,同一个ID会因为ques_id=3和ques_id=17分成两行显示,而且直接在WHERE里加fs.QUES_ID=3 AND fs.ANS_TEXT='Non-MFG' AND fs.QUES_ID=17 AND fs.ANS_TEXT='Yes'肯定不行——因为同一行只能有一个ques_id,永远匹配不到同时满足两个条件的行!
咱们需要先把同一ID的两个答案合并到同一行的不同列,再筛选出同时符合两个条件的ID,或者先筛选符合条件的ID,再合并答案。
方法一:用INNER JOIN筛选+直接列展示(最简单易懂)
这种方法通过两次关联ADD_ANSW表,分别获取满足两个条件的记录,自动过滤掉不满足其中任何一个条件的ID,还能直接把两个答案放到不同列:
SELECT p.ID, ISNULL(dbo.fnRemovePatternFromString(p.Last_Name, '%[,-.'']%'), '') AS [Last], ISNULL(dbo.fnRemovePatternFromString(p.First_Name, '%[,-.'']%'), '') AS [First], ISNULL(dbo.fnRemovePatternFromString(p.Middle_Initial, '%[,-.'']%'), '') AS [Middle], fs3.ANS_TEXT AS [Q3_Answer], -- ques_id=3的答案列 fs17.ANS_TEXT AS [Q17_Answer] -- ques_id=17的答案列 FROM person p INNER JOIN person_facilities pf ON p.ID = pf.ID -- 只关联满足ques_id=3且ans_text='Non-MFG'的记录 INNER JOIN dbo.ADD_ANSW fs3 ON p.id = fs3.id AND fs3.QUES_ID = 3 AND fs3.ANS_TEXT = 'Non-MFG' -- 只关联满足ques_id=17且ans_text='Yes'的记录 INNER JOIN dbo.ADD_ANSW fs17 ON p.id = fs17.id AND fs17.QUES_ID = 17 AND fs17.ANS_TEXT = 'Yes' WHERE pf.Current_status = 'Employed'
为什么这个方法有效?
INNER JOIN会只保留同时匹配两个关联条件的ID,也就是必须同时存在ques_id=3且ans='Non-MFG'和ques_id=17且ans='Yes'的记录。- 直接把两个关联表的
ANS_TEXT分别命名成不同列,不需要额外处理行转列的逻辑,对初学者特别友好。
方法二:用CASE WHEN行转列+EXISTS筛选(更灵活)
如果之后需要扩展更多ques_id的列,这种方法更灵活,先把所有答案转到同一行的不同列,再用EXISTS确保ID满足两个条件:
SELECT p.ID, ISNULL(dbo.fnRemovePatternFromString(p.Last_Name, '%[,-.'']%'), '') AS [Last], ISNULL(dbo.fnRemovePatternFromString(p.First_Name, '%[,-.'']%'), '') AS [First], ISNULL(dbo.fnRemovePatternFromString(p.Middle_Initial, '%[,-.'']%'), '') AS [Middle], -- 用CASE WHEN把ques_id=3的答案提取到单独列 MAX(CASE WHEN fs.QUES_ID = 3 THEN fs.ANS_TEXT END) AS [Q3_Answer], -- 用CASE WHEN把ques_id=17的答案提取到单独列 MAX(CASE WHEN fs.QUES_ID = 17 THEN fs.ANS_TEXT END) AS [Q17_Answer] FROM person p INNER JOIN person_facilities pf ON p.ID = pf.ID LEFT JOIN dbo.ADD_ANSW fs ON p.id = fs.id AND (fs.QUES_ID = 17 OR fs.QUES_ID = 3) WHERE pf.Current_status = 'Employed' -- 检查当前ID是否存在ques_id=3且ans='Non-MFG'的记录 AND EXISTS ( SELECT 1 FROM dbo.ADD_ANSW fs3 WHERE fs3.id = p.id AND fs3.QUES_ID = 3 AND fs3.ANS_TEXT = 'Non-MFG' ) -- 检查当前ID是否存在ques_id=17且ans='Yes'的记录 AND EXISTS ( SELECT 1 FROM dbo.ADD_ANSW fs17 WHERE fs17.id = p.id AND fs17.QUES_ID = 17 AND fs17.ANS_TEXT = 'Yes' ) GROUP BY p.ID, [Last], [First], [Middle]
关键部分解释
CASE WHEN:针对每个ques_id,只提取对应行的ANS_TEXT,其他行返回NULL,再用MAX()把同一ID的两个答案合并到同一行(因为MAX()会忽略NULL)。EXISTS:用来检查同一个ID是否存在满足条件的行,不会像之前的WHERE那样限制同一行必须同时满足两个条件。
初学者小提示
- 当需要同一个实体(比如这里的
person.ID)满足不同行的多个条件时,不要在WHERE里直接写矛盾的行条件(比如同时要求ques_id=3和ques_id=17),要用INNER JOIN多次、EXISTS或者GROUP BY + HAVING来实现。 - 行转列的需求,
CASE WHEN比PIVOT更直观,适合新手理解和扩展。
内容的提问来源于stack exchange,提问作者Michele
相关产品推荐
相关产品推荐

