sql查询即使在某一天没有付款也能获得一个月的每日付款

时间:2009-12-03 20:19:03

标签: sql sql-server sql-server-2005

我正在使用SQL Server 2005并尝试编写一个查询,我想要检索给定月份的付款。我目前有:

select sum(p1.paymentamount) as subtotal, 
       CONVERT(char(10), p1.paymentdate, 103) as paymentdate
  from tblpayment p1
 where 1=1
   and p1.paymentdate >= @fromdate
   and p1.paymentdate <= @todate
group by p1.paymentdate
order by p1.paymentdate

架构:

CREATE TABLE [dbo].[tblPayment]
( 
    [paymentid] [int] IDENTITY(1,1) NOT NULL, 
    [userid] [int] NULL , 
    [paymentdate] [datetime] NOT NULL, 
    [paymentamount] [int] NULL, 
    [paymenttype] [varchar](50) NULL, 
    [paymentnotes] [varchar](200) NULL, 
    [paymentcurrency] [nchar](10) NULL 
) 

这个查询给了我想要的东西,但它没有给我没有付款的日期。我想要的是一个查询,即使当天没有付款也会给我所有日子,并且jut会在当天显示小计为0。

还有另一个问题。付款货币不同。那么我怎样才能在查询中有另一个列,它根据传入的@currency参数给出了eurototal和sterlingtotal?假设表中有一列“paymentcurrency”

5 个答案:

答案 0 :(得分:1)

如果没有任何付款的日期在tblPayment中没有虚拟记录,那么这些日期将不会出现在仅从tblPayment中选择的查询中。

我通过创建一个单独的表来处理这个,除了日期(每个日期一行),检查以确保我有所有日期来覆盖我的查询,然后LEFT JOINing我的主表(在这种情况下) tblPayment)在日期表上:

SELECT * FROM tblPayment LEFT OUTER JOIN tblDates
ON tblPayment.PaymentDate = tblDates.PossibleDate

使用GROUP BY可以增强这个基本想法,以获得您想要的摘要数字。

答案 1 :(得分:1)

你必须倒退。为了获取不存在的日期的行,您需要将它们外部连接到具有这些日期的行。要进行外连接,您需要有一个要连接的序列。由于您没有序列,因此需要创建一个序列。

要创建该序列,您有两个选择:

  • 创建一个静态日期序列并将其存储在永久表中(Larry的回答);或
  • 使用现有的数字序列(例如spt_values)即时创建一个。

让我们假设你想要第二种方法的灵活性。这是我用于这类事情的常见片段:

SELECT DATEADD(DAY, v.number, @fromdate)
FROM master.dbo.spt_values v
WHERE v.type = 'P'
AND v.number <= DATEDIFF(DAY, @fromdate, @todate)

现在只需在CTE中投入并加入它:

WITH Dates_CTE (dt) AS
(
    -- // Paste the snippet above in here
)
SELECT d.dt AS paymentdate, ISNULL(SUM(p.paymentamount), 0) AS subtotal
FROM Dates_CTE d
LEFT JOIN tblpayment p
ON p.paymentdate = d.dt
GROUP BY d.dt
ORDER BY d.dt

(更新:我在主查询中省略了WHERE子句,因为它在技术上由连接处理,但在某些情况下,通过将其保留在其中可能会获得更好的性能)

关于货币转换,请查找PIVOT的语法。


更新PIVOT:您应该能够将整个查询括在括号中,然后转到:

SELECT paymentdate, [Euro] AS euroamount, [Pound] as poundamount
FROM
(
    -- // Insert the full query from above in here
) p
PIVOT
(
    SUM(subtotal)
    FOR paymentcurrency IN ([Euro], [Pound])
) AS pvt

如果不确切知道那里有什么类型的数据,很难验证,但请尝试将其作为起点。

答案 2 :(得分:1)

这是一种方法

创建以下功能:

CREATE FUNCTION [dbo].[DateTable] (@StartDate DATETIME, @endDate DATETIME)
RETURNS @Itms TABLE
(
    TheDate DATETIME
)
AS
BEGIN
    DECLARE @theDate DATETIME

    SET @TheDate = @StartDate
    WHILE @TheDate <= @endDate
    BEGIN
        INSERT @Itms VALUES (@theDate)
        SET @TheDate =dateAdd(d,1,@theDate)
    END
    RETURN
END;

然后这是一个应该做你想做的查询

select sum(p1.paymentamount) as subtotal, 
       CONVERT(char(10), p1.paymentdate, 103) as paymentdate
  from 
    (select * from tblpayment p1
      where 1=1
      and p1.paymentdate >= @fromDate
      and p1.paymentdate <= @toDate
     union
        select theDate as paymentDate,0 as paymentAmount 
          from dbo.dateTable (@fromDate,@toDate)
    ) p1
group by p1.paymentdate

答案 3 :(得分:0)

尝试这样的事情吗?

select sum(p1.paymentamount) as subtotal, 
       CASE WHEN (CONVERT(char(10), p1.paymentdate, 103) = 0) THEN 'No Sale'
       ELSE 
        CONVERT(char(10), p1.paymentdate, 103)

       END as paymentdate 
FROM   tblpayment
where  paymentdate BETWEEN @fromdate and @todate

答案 4 :(得分:0)

如前所述,您必须使用单独的表(临时或永久)。货币转换可以使用CASE语句完成。看看下面(我编制了转换因子;)

declare @dates table (dateitem datetime)
declare @lower datetime
declare @upper datetime
set @lower = '12/1/9'
set @upper = '12/31/9'

while @lower <= @upper
  begin
    insert into  @dates values (@lower)
    set @lower = dateadd(day, 1, @lower)
  end


select dateitem, paymentcurrency,
   paymentindollars = case paymentcurrency when 'dollars' then total when 'euro' then total * 1.7 else 0 end,
   paymentineuros = case paymentcurrency when 'dollars' then total * 0.73 when 'euro' then total else 0 end
   from 
   (select dateitem, paymentcurrency, sum(paymentamount) as total
    from @dates DT left join tblpayment on DT.dateitem = tblpayment.paymentdate group by dateitem, paymentcurrency
    ) IQ order by dateitem

需要注意的注意事项:

  • 您的payementdate可能有时间 它你必须删除 (通过强制转换)使加入/分组正常工作
  • 要使转换正常工作,您必须将不同的货币类型分开,您可以随时将它们包装在另一个sql中以获得当天的总计
  • 货币兑换通常只适用于当天,因此在一段时间内应用一般转换不会给您带来良好的财务结果,只有不错的大概数字(即不要尝试将其存入您的税款;)

希望有所帮助。