我正在使用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”
答案 0 :(得分:1)
如果没有任何付款的日期在tblPayment中没有虚拟记录,那么这些日期将不会出现在仅从tblPayment中选择的查询中。
我通过创建一个单独的表来处理这个,除了日期(每个日期一行),检查以确保我有所有日期来覆盖我的查询,然后LEFT JOINing我的主表(在这种情况下) tblPayment)在日期表上:
SELECT * FROM tblPayment LEFT OUTER JOIN tblDates
ON tblPayment.PaymentDate = tblDates.PossibleDate
使用GROUP BY可以增强这个基本想法,以获得您想要的摘要数字。
答案 1 :(得分:1)
你必须倒退。为了获取不存在的日期的行,您需要将它们外部连接到具有这些日期的行。要进行外连接,您需要有一个要连接的序列。由于您没有序列,因此需要创建一个序列。
要创建该序列,您有两个选择:
让我们假设你想要第二种方法的灵活性。这是我用于这类事情的常见片段:
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
需要注意的注意事项:
希望有所帮助。