SQL查询一对多关系连接没有重复

时间:2013-07-23 18:54:10

标签: sql sql-server sql-server-2008 tsql join

我在SQL Server 2008中运行查询..我有一个sales表和一个payments表..有时销售有多种付款方式(部分礼品卡+部分现金或部分信用卡) +部分现金等..)所以我想要做的是在表格中列出每笔销售的销售和付款。

如果我执行LEFT JOIN ON sales.SaleID = payments.SaleID,当有多个匹配的付款行时,我会获得重复的销售行数。

所以我一直在做的是获取所有销售额以及与(SELECT COUNT(*) FROM payments WHERE payments.SaleID = sales.SaleID) AS NumOfPayments匹配的付款行数。然后在我的PHP脚本中,我检查付款的数量,如果是> 1我然后运行另一个查询来获取付款详细信息。

我想要的输出看起来像这样

-----------------------------------------------------
| SaleID |  SaleDate  | Amount  | Payments          |
-----------------------------------------------------
|    123 | 2013-07-23 | $ 19.99 | Cash:     $ 19.99 |
|    124 | 2013-07-23 | $  7.53 | Cash:     $  7.53 |
|    125 | 2013-07-23 | $174.30 | Credit:   $124.30 |
|        |            |         | GiftCard: $ 50.00 |
|    126 | 2013-07-23 | $ 79.99 | Cash:     $ 79.99 |
|    127 | 2013-07-23 | $100.00 | Credit:   $ 90.00 |
|        |            |         | Cash:     $ 10.00 |
-----------------------------------------------------

如果销售125和127有多个付款列出,但销售信息只出现一次,并且每次付款都不重复。

salespayments表格如下所示:

Sales                              Payments
---------------------------------  --------------------------------------------
| SaleID |  SaleDate  | Amount  |  | PaymentID | SaleID | PmtMethod |  PmtAmt |
---------------------------------  --------------------------------------------
|    123 | 2013-07-23 | $ 19.99 |  |       158 |    123 |        4  | $ 19.99 |
|    124 | 2013-07-23 | $  7.53 |  |       159 |    124 |        4  | $  7.53 |
|    125 | 2013-07-23 | $174.30 |  |       160 |    125 |        2  | $124.30 |
|    126 | 2013-07-23 | $ 79.99 |  |       161 |    125 |        3  | $ 50.00 |
|    127 | 2013-07-23 | $100.00 |  |       162 |    126 |        4  | $ 79.99 |
---------------------------------  |       163 |    127 |        2  | $ 90.00 |
                                   |       164 |    127 |        4  | $ 10.00 |
                                   --------------------------------------------

我觉得如果我能用SQL做它会更快。有没有办法用纯SQL实现这一点,而不必使用服务器端代码来运行条件查询。

4 个答案:

答案 0 :(得分:1)

我不会混合数据检索和数据显示,这是我认为你在问的问题。您是否有某种列表明应首先显示哪些付款?我想的是:

SELECT columnlist, 
rn = ROW_NUMBER() OVER (PARTITION BY sales.salesID ORDER BY payment.paymentID)
FROM sales JOIN payments ON sales.salesID=payments.salesID

然后,在您的GUI中,只显示RN = 1的前3列的值,并删除RN> 1的值。 1。

答案 1 :(得分:0)

在界面中执行此操作可能更容易。

您想要的基本查询是:

  select s.saleID, s.SaleDate, s.Amount,
         p.PaymentType, p.PaymentAmount,
         ROW_NUMBER() over (partition by p.SaleId order by p.PaymentAmount desc) as seqnum
  from sales s join
       payments p
       on p.saleID = s.saleId
  order by 1, 2

但是,您正在尝试删除字段。为此,您需要将所有字段转换为字符串,然后检查每个SaleId的第一行中是哪一个:

select (case when seqnum > 1 then '' else CAST(SaleId as varchar(255)) end) as SaleId,
       (case when seqnum > 1 then '' else CONVERT(varchar(10), SaleDate, 121) end) as SaleDate,
       (case when seqnum > 1 then '' else '$'+STR(amount, 6, 2) end) as Amount,
       PaymentType, PaymentAmount
from (select s.saleID, s.SaleDate, s.Amount,
             p.PaymentType, p.PaymentAmount,
             ROW_NUMBER() over (partition by p.SaleId order by p.PaymentAmount desc) as seqnum
      from sales s join
           payments p
           on p.saleID = s.saleId
     ) sp
order by SaleId, SaleDate;

这不是SQL的设计类型。 SQL与表一起使用,其中所有列具有相同的含义。在这里,您将根据其在销售中的位置为该列引入不同的含义。是的,SQL可以做到。不,这不容易。

答案 2 :(得分:0)

以下查询将提供您需要的结果,您需要跳过SalesIDToSort列。

  ;with SalesData
  as
  (
    select 
      Sales.SalesID, Sales.SalesDate, Sales.TotalAmount, Payments.PaymentMode, Payments.Amount,
      Row_Number() over(Partition by Sales.SalesID order by Payments.PaymentID) RowNum
    from 
      Payments
      inner join Sales on Payments.SalesID = Sales.SalesID
  )
  select SalesID, SalesDate, TotalAmount, PaymentMode, Amount, SalesID SalesIDToSort
  from 
    SalesData
  where
    SalesData.RowNum = 1
  union all
  select null, null, null, PaymentMode, Amount, SalesID SalesIDToSort
  from 
    SalesData
  where
    SalesData.RowNum > 1
  order by 6

Working demo

答案 3 :(得分:0)

您可以按照格式的功能尝试分组:

select salesid, salesDate, Amount, FORMAT(payment, 9999.999) as payments
from FROM payments 
WHERE payments.SaleID = sales.SaleID
group by salesid;

如果您将FORMAT作为可用功能,这可能会有效。