使用 SQL WITH 子句,然后在一个过程中将其与 SELECT 语句合并

Using SQL WITH clause then merging it with SELECT statement in one procedure

我有一个 table,其中 XML 列的类型为 nvarchar(max) ContactInformationXML。我设法解析此列以使用此查询 CountryMarket 获取我想要的数据:

WITH CastToXML AS (
    SELECT ContactInformationXML, TRY_CAST(ContactInformationXML AS xml) AS x
        FROM Archive_ProgUsers
        WHERE ContactInformationXML IS NOT NULL AND ContactInformationXML <> '' AND ContactInformationXML <> 'Admin - Old Program in Use' AND ContactInformationXML <> 'Admin - Admin Edits'
)
SELECT h.p.value('(/user/contact/@CountryMarket)[1]','nvarchar(max)') AS CountryMarket
    FROM CastToXML
        cross apply x.nodes('/user/contact[1]') AS h(p)

但是,既然我有了该列,我需要将它与同一过程中的另一个查询结合起来以显示一个 table。这是第二个查询:

SELECT DISTINCT
    user_id,
    email,
    app_id,
    ContactInformationXML,
    install_code,
    programStarts
FROM Archive_ProgUsers
INNER JOIN Archive_Installations ON Archive_ProgUsers.id = Archive_Installations.user_id
INNER JOIN (
    SELECT DISTINCT inst_id 
        , COUNT(CASE WHEN Archive_Hits.type <> 'New' AND Archive_Hits.accessed_on BETWEEN CAST(@startdate AS DATE) AND CAST(@enddate AS DATE) THEN 1 END) AS programStarts
    FROM Archive_Hits
    GROUP BY Archive_Hits.inst_id 
) AS hitsCount ON hitsCount.inst_id = Archive_Installations.id
WHERE programStarts > 0
ORDER BY programStarts DESC

我不能使用 UNION 或 UNION ALL,因为我必须在每个列表中有相同数量的表达式。

如何将这 2 个查询合并到一个过程中,returns 一个结果 table 看起来像这样?

更新 联系信息示例XML 数据:

<user Userid="John Smith"> <contact FirstName="John" LastName="Smith" RegistrationEmailAddress="j.smith@example.com" DisplayEmailAddress="j.smith@example.com" Company="Google" Title="" PhoneNum="+6666666666" FaxNum="" Address1="example USA, 77" Address2="" City="Earth" StateName="testing;" StateCode="USA" ZipCode="00000" CountryCode="US" CountryMarket="North America" DateModified="2020-03-16T16:35:00"/> </user>

不知道联系信息 XML 的结构,很难猜测结果应该是什么,但根据您的查询,您可以这样做:

With CastToXML AS (
    SELECT user_id, ContactInformationXML, TRY_CAST(ContactInformationXML AS xml) AS x
        FROM Archive_ProgUsers
        WHERE ContactInformationXML IS NOT NULL AND ContactInformationXML <> '' AND ContactInformationXML <> 'Admin - Old Program in Use' AND ContactInformationXML <> 'Admin - Admin Edits'
),
Market AS (
SELECT user_id, h.p.value('(/user/contact/@CountryMarket)[1]','nvarchar(max)') AS CountryMarket
    FROM CastToXML
        cross apply x.nodes('/user/contact[1]') AS h(p)
)
SELECT DISTINCT
    user_id,
    email,
    app_id,
    --ContactInformationXML,
    install_code,
    programStarts,
    CountryMarket
FROM Archive_ProgUsers
INNER JOIN Archive_Installations ON Archive_ProgUsers.id = Archive_Installations.user_id
INNER JOIN (
    SELECT DISTINCT inst_id 
        , COUNT(CASE WHEN Archive_Hits.type <> 'New' AND Archive_Hits.accessed_on BETWEEN CAST(@startdate AS DATE) AND CAST(@enddate AS DATE) THEN 1 END) AS programStarts
    FROM Archive_Hits
    GROUP BY Archive_Hits.inst_id 
) AS hitsCount ON hitsCount.inst_id = Archive_Installations.id
LEFT JOIN Market
  ON Market.user_id = Archive_ProgUsers.user_id
WHERE programStarts > 0
ORDER BY programStarts DESC

您似乎只有一个值要从 XML 中提取出来。所以你可以非常简单地做到这一点,将 TRY_CAST 放在 CROSS APPLY 中并在其上使用 .values

您也不需要 WHERE,因为在这些情况下 TRY_CAST 将 return null

SELECT
    user_id,
    email,
    app_id,
    ContactInformationXML = v.x.value('(/user/contact/@CountryMarket)[1]','nvarchar(max)'),
    install_code,
    programStarts
FROM Archive_ProgUsers
INNER JOIN Archive_Installations ON Archive_ProgUsers.id = Archive_Installations.user_id
INNER JOIN (
    SELECT inst_id 
        , COUNT(CASE WHEN Archive_Hits.type <> 'New' AND Archive_Hits.accessed_on BETWEEN CAST(@startdate AS DATE) AND CAST(@enddate AS DATE) THEN 1 END) AS programStarts
    FROM Archive_Hits
    GROUP BY Archive_Hits.inst_id 
) AS hitsCount ON hitsCount.inst_id = Archive_Installations.id
CROSS APPLY (VALUES (TRY_CAST(ContactInformationXML AS xml)) ) v(x)
WHERE programStarts > 0
ORDER BY programStarts DESC

我建议您重新考虑那些 DISTINCT。它们可能是不必要的。如果您得到重复项,您应该仔细查看您的联接。不要只是扔 DISTINCT 来消除重复项。