【问题标题】:return 1 row from multiple case statements从多个 case 语句中返回 1 行
【发布时间】:2016-06-15 17:51:58
【问题描述】:

在下面的端口中带有 case 语句的查询中,我试图弄清楚当 SegmentType 不匹配时如何不返回空值。

QRSubscriberTag、MLKSubscriberTag、QTMSubscriber Tag,实际上是一个Tags的表,由它们的SegID和与SegID关联的segmentType唯一标识。我将外部应用与调用 FOR XML PATH('') 的子查询一起使用,以将与特定标签相关的标签连接在一起。

这种方法的缺陷是当标签不是例如 QRSubscriberTag 时,会在 QRSubscriberTag 列中创建一个空记录。

QRSubscriberTag|QR01|MLKSubscriberTag|MLK01|QTMSubscriberTag|QTM01|QTM02
NULL           |NULL|NULL            |{Data}|null           |FH   |45
TKP ;OCP ;OCR ;|R   |NULL            |null |null            |null |null

我希望看到的是 1 行中的所有数据

QRSubscriberTag|QR01|MLKSubscriberTag|MLK01|QTMSubscriberTag|QTM01|QTM02
TKP ;OCP ;OCR ;|R   |NULL            |{Data}|null            |FH  |45

下面是我的代码

SET NOCOUNT ON

USE [Apps]

SELECT [BusRuleEnforceID], [FormatType], [Format],
        [tag], [TagValue], Operator,
       [QRSubscriberTag],[QR01],
       [MLKSubscriberTag],[MLK01], 
       [QTMSubscriberTag],[QTM01],[QTM02]
FROM
(
    SELECT 
        DISTINCT main.BusRuleEnforceID, 
        main.FormatType, 
        main.Format, 
        main.tag,
        main.TagValue,
        main.Operator,
        CASE
            WHEN seg.SegmentType = 'QR' THEN LEFT(SegsubscriberTags.list, LEN(SegsubscriberTags.list))
        END AS [QRSubscriberTag],
        CASE
            WHEN seg.SegmentType = 'MLK' THEN LEFT(SegsubscriberTags.list, LEN(SegsubscriberTags.list)-1)
        END AS [MLKSubscriberTag],
        CASE
            WHEN seg.SegmentType = 'QTM' THEN LEFT(SegsubscriberTags.list, LEN(SegsubscriberTags.list)-1)
        END AS [QTMSubscriberTag],
        c.ItemName as [SegmentId],
        Case
            WHEN c.ItemValue is not null and len(rtrim(c.ItemValue)) > 0 THEN c.ItemValue
            ELSE LEFT(TagOptions.list, LEN(TagOptions.list)-1)
        END as [Tags]
    FROM
        BMT_BusRulemaineria main 
    LEFT OUTER JOIN
        BMT_BusRuleServiceType st
    ON st.MappingmaineriaID = main.BusRuleEnforceID
    LEFT OUTER JOIN
        BMT_BusRuleSegment seg
    ON seg.BusRuleEnforceID = main.BusRuleEnforceID
    LEFT OUTER JOIN
        BMT_BusRuleItem c
    ON c.BusRuleEnforceSegID = seg.BusRuleEnforceSegID
    LEFT OUTER JOIN
        BMT_BusRuleItemOption co
    ON c.BusRuleItemId = co.BusRuleItemId
    OUTER APPLY 
    ( 
            SELECT 
            IsNull(co2.Tag, '{Unknown}') + ISNULL('=' + co2.TagValue, '') + ':' + IsNull(co2.ItemValue, '')+ ';' AS [text()] 
            FROM 
                BMT_BusRuleItemOption co2 
            WHERE 
                co.BusRuleItemId = co2.BusRuleItemId
            ORDER BY 
                co2.BusRuleItemId 
            FOR XML PATH('') 
        ) TagOptions (list) 
    OUTER APPLY 
    (
            SELECT 
            IsNull(porttag.Tag, '{Unknown}') + ' ' + ISNULL(porttag.Operator, '') + ' ' + IsNull(porttag.TagValue, '') + ';' AS [text()]
            FROM 
                BMT_BusRuleSegmentTag porttag 
            WHERE 
                seg.BusRuleEnforceSegID = porttag.BusRuleEnforceSegID
            ORDER BY 
                porttag.BusRuleEnforceSegID 
            FOR XML PATH('')
    ) SegsubscriberTags (list) 
        WHERE main.BusRuleEnforceID = 632563
    AND main.TagTypeId = 1
) AS QRSourceTable
PIVOT
(
    max([Tags])
    FOR [SegmentId] IN ([QR01], [MLK01], [QTM01], [QTM02])
) AS QRPivotTable
ORDER BY 
    [TagTypeId], [BusRuleEnforceID]

编辑:完整结果集 注意:QRSubscriber、MLKSubscriber 和 QTMSubscriber 标签都有唯一的 SegID。

<table><tbody><tr><th>FormatType</th><th>Format</th><th>Version</th><th>AmtCode</th><th>Date</th><th>LocationIdentifier</th><th>TagType</th><th>tag</th><th>TagValue</th><th>Operator</th><th>InfoCode</th><th>QRSubscriberTag</th><th>QR01</th><th>QR02</th><th>QR03</th><th>QR04</th><th>QR05</th><th>QR06</th><th>QR07</th><th>MLKSubscriberTag</th><th>MLK01</th><th>QTMSubscriberTag</th><th>QTM01</th><th>QTM02</th></tr><tr><td>DN</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>TIR</td><td>RPSAMN</td><td>NULL</td><td>exists</td><td>78</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>{Data}</td><td>NULL</td><td>TRH</td><td>675</td></tr><tr><td>DN</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>TIR</td><td>RPSAMN</td><td>NULL</td><td>exists</td><td>78</td><td>TKRARAP not exists TKRALAP not exists TKRADAP not exists </td><td>J</td><td>SKU</td><td>34</td><td>NULL</td><td>NULL</td><td>SILMULTU:2;SILMHLTU:67</td><td>TOPALD:{Data};QORITK{Data}</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td><td>NULL</td></tr></tbody></table>

【问题讨论】:

  • 嗯,不要在你的case语句中使用NULL?您可以使用空白字符串,例如 '' 或您选择的任何其他标记值。
  • 忘记删除它们。在这种情况下,else null 不做任何事情。例如,如果我这样做:CASE WHEN port.SegmentType = 'QR' THEN LEFT(SegDependantTags.list, LEN(SegDependantTags.list)) END AS [QRSubscriberTag] 结果将是相同的。 Case 语句在 Segment 不是 QR 的情况下创建空值。
  • 确保发布您实际使用的代码。这不会通过语法检查。您正在引用一个名为“端口”的表或别名,该表或别名在您的 from 子句中的任何位置都不存在。
  • 现在您添加的输出与您的代码将生成的相同字段不匹配。

标签: sql-server case dynamic-columns outer-apply


【解决方案1】:

当比较不匹配时,使用 ELSE 子句分配一个默认值,如下所示:

CASE WHEN port.SegmentType = 'QR' THEN 
  LEFT(SegDependantTags.list, LEN(SegDependantTags.list))
ELSE 'Your Value Rather Than NULL Goes Here'
END AS [QRSubscriberTag],

【讨论】:

  • 此方法会创建多个列。这个想法是把它压缩成一列。
  • 嗯,我在你的问题中没有看到。
  • 我所说的我想看到的是 1 行中的所有数据
【解决方案2】:

似乎您不想在QRSourceTable 子查询中使用Distinct,而是想在订阅者标签字段上使用Group ByMAX 聚合函数:

SELECT 
        main.BusRuleEnforceID, 
        main.FormatType, 
        main.Format, 
        main.tag,
        main.TagValue,
        main.Operator,
        max(CASE
            WHEN port.SegmentType = 'QR' THEN LEFT(SegDependantTags.list, LEN(SegDependantTags.list))
        END) AS [QRSubscriberTag],
        max(CASE
            WHEN port.SegmentType = 'MLK' THEN LEFT(SegDependantTags.list, LEN(SegDependantTags.list)-1)
        END) AS [MLKSubscriberTag],
        max(CASE
            WHEN port.SegmentType = 'QTM' THEN LEFT(SegDependantTags.list, LEN(SegDependantTags.list)-1)
        END) AS [QTMSubscriberTag],
        c.ItemName as [SegmentId],
        Case
            WHEN c.ItemValue is not null and len(rtrim(c.ItemValue)) > 0 THEN c.ItemValue
            ELSE LEFT(TagOptions.list, LEN(TagOptions.list)-1)
        END as [Tags]
from
     ...
WHERE main.BusRuleEnforceID = 632563
    AND main.TagTypeId = 1
GROUP BY main.BusRuleEnforceID, 
        main.FormatType, 
        main.Format, 
        main.tag,
        main.TagValue,
        main.Operator

【讨论】:

  • 使用这种方法,我看到了相同的结果。我最近通过对每个 SegmentType 使用子查询而不是使用 SegDependantTags.List 获得了我最近想要的结果,但是由于子查询的过度使用,执行时间需要 30 分钟而不是 15 秒才能找到 38k 条记录。
  • 如果您仍然使用此方法获得附加记录,这意味着您从“主”表别名中选择的字段之一也必须与另一条记录不同。您没有在问题中显示结果表中的所有字段,所以我在猜测。查询输出中的哪些字段必须是唯一的?从那个问题开始,然后从那里开始工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 1970-01-01
相关资源
最近更新 更多