具有不同列数的多个查询的联合结果

问题描述

我正在编写 sql 来报告类似于以下格式的数据。以“P”开头的行是特定供应商的汇总行,用于其下方与付款或该供应商关联的相应汇款“R”行。例如,P 行上的 PAID_AMT 金额是“NW Forest Supplies”的总和值(1000.50 = 相应 R 行的总和 110 + 800 + 100.50 = 1000.50)。我开始以 UNION 查询的形式执行此操作,但挑战在于“P”行代表的字段与“R”行代表的字段不同,因此我正在努力将数据组合在一起。

以 'C' 开头的最后一行是所有行的总体摘要,我也在努力解决并且不正确。根据示例,它应该对来自“P”行的总 PAID_AMT 值求和,即 2056.00 (1000.50 + 55 + 1000.50),然后输出付款次数的总计数 (3),然后最终得出总付款数汇款 - 在本例中为 7。

也许在最终结果中使用CTE和union比较好,或者使用临时表将'P'和'R'数据的数据插入到自己的表中,然后从?

报告输出方式的示例:

enter image description here

SELECT
    'P','CRD','PayerName.Payables',A.ADDRESS4,A.PYMNT_ID_REF,SUM(B.PAID_AMT),A.REMIT_vendOR,CAST(B.REMIT_ADDR_SEQ_NUM AS VARCHAR),A.NAME1,'USD'
FROM
    PS_PAYMENT_TBL                A
    INNER JOIN PS_PYMNT_VCHR_XREF B
        ON B.PYMNT_ID = A.PYMNT_ID
           AND A.BANK_SETID = B.BANK_SETID
           AND A.BANK_CD = B.BANK_CD
           AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE A.PYMNT_DT > '01/12/2021'
GROUP BY
    A.REMIT_vendOR,A.NAME1
UNION
SELECT
    'R',C.INVOICE_ID,C.INVOICE_DT,C.GROSS_AMT,C.DSCNT_AMT,B.VOUCHER_ID,C.PO_ID,'',''
FROM
    PS_PYMNT_VCHR_XREF        B
    INNER JOIN PS_PAYMENT_TBL A
        ON B.PYMNT_ID = A.PYMNT_ID
           AND A.BANK_SETID = B.BANK_SETID
           AND A.BANK_CD = B.BANK_CD
           AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
    INNER JOIN PS_VOUCHER     C
        ON B.VOUCHER_ID = C.VOUCHER_ID
           AND C.BUSInesS_UNIT = B.BUSInesS_UNIT
WHERE A.PYMNT_DT > '01/12/2021'
UNION
SELECT
    'C',SUM(A.PAID_AMT),COUNT(A.PAID_AMT),COUNT(??)
FROM
    PS_PYMNT_VCHR_XREF        A
    INNER JOIN PS_PAYMENT_TBL B
        ON B.PYMNT_ID = A.PYMNT_ID
           AND A.BANK_SETID = B.BANK_SETID
           AND A.BANK_CD = B.BANK_CD
           AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE A.PYMNT_DT > '01/12/2021'
GROUP BY B.NAME1
ORDER BY 7,1

编辑 1/17/21:

我稍微修改sql,并相信我的代码的各个部分都可以工作,但我正在努力考虑如何以与示例中说明的相同的方式将这些组合起来,并在每个付款下方显示汇款。

UNION 是我能想到的唯一垂直合并数据的功能,但我需要能够将每个相应付款行下方的汇款分组,我不知道我可以用什么方法来做到这一点。另外值得一提的是,Payment 和 Remittances 查询的列是不同的(列数和类型)并且并不总是相互关联。

--Payment:
SELECT B.ADDRESS4,B.PYMNT_ID_REF,B.REMIT_vendOR,A.REMIT_ADDR_SEQ_NUM,B.NAME1
FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE B.PYMNT_DT > '2021-01-03'
--AND A.PYMNT_ID = '0000263556'
GROUP BY B.ADDRESS4,B.NAME1

--Remittances:
SELECT 2,C.PO_ID
FROM PS_PYMNT_VCHR_XREF B
INNER JOIN PS_PAYMENT_TBL A ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
INNER JOIN PS_VOUCHER C ON B.VOUCHER_ID = C.VOUCHER_ID AND C.BUSInesS_UNIT = B.BUSInesS_UNIT
WHERE A.PYMNT_DT > '2021-01-03'
--AND A.PYMNT_ID = '0000263556'


--Control data:
WITH CONTROLTOTALS AS (
SELECT  SUM(A.PAID_AMT) AS TOT_PAID_AMT
FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE B.PYMNT_DT > '2021-01-03' ),CONTROLCOUNT1 AS (

SELECT COUNT(PYMNT_ID_REF) AS PYMNT_COUNT
FROM PS_PAYMENT_TBL B
WHERE B.PYMNT_DT > '2021-01-03'
AND PYMNT_ID <> '' ),CONTROLCOUNT2 AS (
SELECT COUNT(*) AS REMIT_COUNT
FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE PYMNT_DT > '2021-01-03'  )

SELECT 'C',A.TOT_PAID_AMT,B.PYMNT_COUNT,C.REMIT_COUNT
FROM CONTROLTOTALS A,CONTROLCOUNT1 B,CONTROLCOUNT2 C

编辑 1/18/21:

以下是这些查询中使用的 3 个表的表结构:

enter image description here

以下是一些示例数据(两个供应商的 2 个付款行(Radiometer America - 付款 ID 023946 和 Highmark Inc. - 付款 ID 023943),以及与每个供应商关联的相应汇款行:

enter image description here

以下是与供应商的每笔付款相关联的示例汇款数据(Highmark 以红色突出显示,有 2 笔汇款,Radiometer America 以绿色突出显示,有 6 笔汇款,示例输出共 8 笔):

enter image description here

这是底部的最终控制(大)总计行。 TOT_PAID_AMT 代表上述每个供应商的总 2 笔付款 (8901.94 + 997,343.44)、总付款次数 (2) 和报告中的总汇款(2 来自 Highmark,6 来自雷度米特美国:

enter image description here

所以现在我需要将所有这些放在一起并以与原始示例相同的方式输出它,并在每个供应商付款下方显示汇款。

这是此特定示例的输出方式,请注意显示的汇款与相应的付款:

enter image description here

所以我拥有所有单独的部分,但我现在需要以这种格式将它们联系在一起,为此我正在努力解决。希望这能提供更清晰的信息。

此处的表格结构/示例文件

https://pastebin.com/Ym9PuKXf

https://pastebin.com/F62467zE

https://pastebin.com/4EBrdyjN

https://pastebin.com/iU20L8Jf

https://pastebin.com/k9P75DAJ

https://pastebin.com/f4Ci6qXd

解决方法

如果我理解正确的话,您有三个查询结果,其中包含多个列,并且您希望将这些结果组合在由 Pipe("|") 分隔符分隔的单个列结果中。 为了实现这一点,我在所有三个查询输出名称“ConcatedValue”中添加了一个额外的列,其中我将所有列的值合并为一个。 然后为了在最后获得 controls 的值,我引入了一个名为 sortid 的列,并且为了维护每个 pymnt_id_ref 的付款和汇款顺序,我引入了一个名为 internalsortid 的列。由于控件表没有 pymnt_id_ref 列,我添加了空值。

我使用您的结果创建了三个名为支付、汇款和控制的表,并通过以下查询获得了您想要的结果:

with cte as(
SELECT 1 SorTID,1 internalsortid,pymnt_id_ref,('P|CRD|Hosp.Payables'+'|'+ ADDRESS4+'|'+ PYMNT_ID_REF+'|'+ colc+'|'+REMIT_VENDOR+'|'+ REMIT_ADDR_SEQ_NUM+'|'+NAME1+'|USD')concatedvalue from payment b
union all
SELECT 1 SortID,2 internalsortid,('R|'+PYMNT_ID_REF +'|'+  INVOICE_ID +'|'+  CONVERT(VARCHAR(10),INVOICE_DT,120)+'|'+  GROSS_AMT +'|'+  DSCNT_AMT +'|'+  VOUCHER_ID +'|'+  PO_ID )
from Remittance
union all
SELECT 3 SortID,3 internalsortid,NULL pymnt_id_ref,('C|'+ TOT_PAID_AMT+'|'+ PYMNT_COUNT+'|'+REMIT_COUNT)concatedvalue from control)
select  concatedvalue from cte order by sortid,internalsortid

预期结果:

enter image description here

由于我没有您的实际表,因此更改后我无法执行您的查询。我在这里分享。但是,如果您有任何数据类型为 int、float 等的列,则需要在将它们合并到单个列中时进行转换。例如,如果 pymnt_id_ref 是一个 int 列,您需要使用以下行作为付款表的 concatedvalue 列:

修改后的查询:

 With Payment as(
SELECT 'P','CRD','Hosp.Payables',B.ADDRESS4,B.PYMNT_ID_REF,SUM(A.PAID_AMT),B.REMIT_VENDOR,A.REMIT_ADDR_SEQ_NUM,B.NAME1,'USD',1 SorTID,('P|CRD|Hosp.Payables'+'|'+ b.ADDRESS4+'|'+ b.PYMNT_ID_REF+'|'+ SUM(A.PAID_AMT)+'|'+b.REMIT_VENDOR+'|'+ a.REMIT_ADDR_SEQ_NUM+'|'+b.NAME1+'|USD')concatedvalue 

FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE B.PYMNT_DT = '2021-01-04'
 --AND A.PYMNT_ID = '0000263556'
   AND B.REMIT_VENDOR IN ('51503A','71520A')
   --AND B.REMIT_VENDOR = '71520A'
  AND B.PYMNT_STATUS NOT IN ('S','V')
     AND (( A.BANK_SETID = 'SHARE'
     AND A.BANK_CD = 'MT'
     AND A.BANK_ACCT_KEY = 'TGC')
     OR ( A.BANK_SETID = 'SHARE'
     AND A.BANK_CD = 'PNC'
     AND A.BANK_ACCT_KEY = '1'))
     --AND D.VENDOR_CLASS <> 'E'
GROUP BY B.ADDRESS4,B.NAME1
--ORDER BY B.NAME1,PYMNT_ID_REF
),Remittance as(
 
--Remittances:
SELECT 2,A.PYMNT_ID_REF,C.INVOICE_ID,C.INVOICE_DT,C.GROSS_AMT,C.DSCNT_AMT,B.VOUCHER_ID,C.PO_ID,1 SortID,('R|'+A.PYMNT_ID_REF +'|'+  C.INVOICE_ID +'|'+   CONVERT(VARCHAR(10),c.INVOICE_DT,120) +'|'+  C.GROSS_AMT +'|'+  C.DSCNT_AMT +'|'+      VOUCHER_ID +'|'+  PO_ID )

FROM PS_PYMNT_VCHR_XREF B
INNER JOIN PS_PAYMENT_TBL A ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
INNER JOIN PS_VOUCHER C ON B.VOUCHER_ID = C.VOUCHER_ID AND C.BUSINESS_UNIT = B.BUSINESS_UNIT
WHERE A.PYMNT_DT = '2021-01-04'
 --AND A.PYMNT_ID = '0000263556'
 --AND B.REMIT_VENDOR = '51503A'
 AND A.PYMNT_ID_REF IN ('023946','023943')
 --OR A.PYMNT_ID_REF =  '023943'
 --ORDER BY PYMNT_ID_REF
 ),--Control data:
CONTROLTOTALS AS (
SELECT  SUM(A.PAID_AMT) AS TOT_PAID_AMT
FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE B.PYMNT_DT = '2021-01-04'
   AND B.PYMNT_ID_REF IN ('023946','023943')),CONTROLCOUNT1 AS (
 
SELECT COUNT(PYMNT_ID_REF) AS PYMNT_COUNT
FROM PS_PAYMENT_TBL B
WHERE B.PYMNT_DT = '2021-01-04'
AND PYMNT_ID <> ''
  AND  B.PYMNT_ID_REF IN ('023946',CONTROLCOUNT2 AS (
SELECT COUNT(*) AS REMIT_COUNT
FROM PS_PYMNT_VCHR_XREF A
INNER JOIN PS_PAYMENT_TBL B ON B.PYMNT_ID = A.PYMNT_ID AND A.BANK_SETID = B.BANK_SETID
     AND A.BANK_CD = B.BANK_CD
     AND A.BANK_ACCT_KEY = B.BANK_ACCT_KEY
WHERE PYMNT_DT = '2021-01-04'  
 AND B.PYMNT_ID_REF IN ('023946','023943') ),finalCTE as(
SELECT SortID,internalsortid,concatedvalue FROM Payment
union all
SELECT SortID,concatedvalue FROM Remittance
union all
SELECT 3 SortID,('C|'+ A.TOT_PAID_AMT+'|'+ B.PYMNT_COUNT+'|'+C.REMIT_COUNT)concatedvalue 
FROM CONTROLTOTALS A,CONTROLCOUNT1 B,CONTROLCOUNT2 C)

select  concatedvalue from finalcte order by sortid,internalsortid
,

您无法在 SQL Server 中进行查询以完全按照您想要的格式返回数据。在 SQL Server(以及任何其他关系 DBMS)中,架构是静态的。 Schema 是表的定义,它是表中列及其类型的列表。 SQL Server 中的查询返回一个包含列及其类型的特定静态列表的表。

在 SQL Server 中,您不能有一个在一行中返回 4 列而在另一行中返回 7 列的查询。

在 SQL Server 中,您的查询不能在一行的列中返回 money 类型的值,而在同一列的另一行中返回 varchar 类型的值。给定列中的所有值必须具有相同的类型。


如果您需要向用户显示此类混合数据,您最好运行三个单独的查询并使用一些报告工具,以您想要的方式整齐地显示数据。


如果您坚持将所有内容都放在一个查询中,您需要决定将哪些值放在哪一列中。

在您的示例中,P 行有 10 列,R 行有 7 列,C 行有 4 列。因此,总的来说,您的查询将生成(至少)10 列。其中一些列的 RC 行将具有 NULL 值。

如果您想将不同类型的值放在同一列中,例如美元金额 (TOT_PAID_AMT) 和一些文本 (CRD),那么您可以使用内置的ConvertFormat 函数。

最后您使用 UNION ALL(而不是 UNION)将来自三个独立表/查询的数据放在一起。

组合

在您的示例中,您没有为查询结果中的所有列指定名称,因此我将在此处输入我的名称。

支付查询返回这些列:

QueryType Col1 Col2 ADDRESS4 PYMNT_ID_REF Col3 REMIT_VENDOR EMIT_ADDR_SEQ_NUM NAME1 Col4

汇款查询返回以下列:

QueryType PYMNT_ID_REF INVOICE_ID INVOICE_DT GROSS_AMT DSCNT_AMT VOUCHER_ID PO_ID

控制查询返回这些列:

QueryType TOT_PAID_AMT PYMNT_COUNT REMIT_COUNT

您可以将它们放入临时表中,或将它们包装在 CTE 中。下面我将它们称为 TablePTableRTableC

现在我们可以写

SELECT
    QueryType,Col1,Col2,ADDRESS4,PYMNT_ID_REF,Col3,REMIT_VENDOR,EMIT_ADDR_SEQ_NUM,NAME1,Col4
FROM TableP

UNION ALL

SELECT
    QueryType,INVOICE_ID,GROSS_AMT,DSCNT_AMT,VOUCHER_ID,PO_ID,NULL,NULL
FROM TableR

UNION ALL

SELECT
    QueryType,TOT_PAID_AMT,PYMNT_COUNT,REMIT_COUNT,NULL
FROM TableC

为文本添加必要的转换,例如 CONVERT(nvarchar(255),TOT_PAID_AMT)。您不必将 NULL 值放在最后,您只需确保 SELECT 中的每个 UNION ALL 返回 10 列。并且这些列具有相同的类型。

排序

当您看到所有三个查询的结果时,您可以继续进行最后一点 - 对它们进行排序。

您希望将 C 值放在最后,并将 R 值放在对应的 P 值之下。通过“对应”,我猜我们可以使用 PYMNT_ID_REF 来匹配它们。 所以,我在这里添加一个辅助列:

SELECT
    'P' AS QueryType,Col4,0 AS SortOrder
FROM TableP

UNION ALL

SELECT
    'R' AS QueryType,0 AS SortOrder
FROM TableR

UNION ALL

SELECT
    'C' AS QueryType,1 AS SortOrder
FROM TableC

ORDER BY
    SortOrder          -- C values last,PYMNT_ID_REF      -- group by PYMNT_ID_REF,QueryType         -- P before R
;

为此,我必须将 PYMNT_ID_REF 值移动到同一列(第 5 列)并四处移动 NULL 值。我最终得到了 12 列。