I'm trying to create a PIVOT TSQL statment that totals the products by date and state/province and provides the AVG Transit Time. Here is what I have so far:
select *
from (select createdate [Date Processed],
stateprovince as [Province],
count(*) as [Total],
avg(datediff(day,createdate,t.eventdate)) as [AVG Delivery],
product
from recipient C left outer join
(select delivid, product, eventdesc, eventdate, eventcode
from deliverystatus
where delivid in (select max(deliv_id)
from deliverystatus
where eventcode = 'DELIVERED'
group by product)) as t ON c.product = t.product
where account = 3519 and consol <>'' and trknum <> '' and C.createdate between '2/4/2016' and '2/4/2016'
group by C.createdate, c.stateprovince, c.product
) as Q
pivot (
count(product)
for [Province] in (NY, IL, GA)
) as PVT
My Result is:
Date Processed Total AVG Transit NY IL GA
2016-02-04 00:00:00.000 1 8 0 0 1
2016-02-04 00:00:00.000 1 11 2 4 1
2016-02-04 00:00:00.000 1 12 0 0 0
2016-02-04 00:00:00.000 1 15 0 0 0
I need the result to be:
Date Processed Total AVG Transit NY IL GA
2016-02-04 00:00:00.000 8 11.5 2 4 2
The ultimate goal is to have the AVG Transit listed by State/Province like this:
Date Processed Total Total AVG NY AVG IL AVG GA AVG
2016-02-04 00:00:00.000 8 11.5 2 8 4 11 2 15
Thanks in advance.
You need to add a GROUP BY clause after the pivot and either take the AVG SUM or MAX value for each output column:
select [Date Processed], SUM(NY+IL+GA) AS [Total], AVG([AVG Delivery]) AS [AVG Delivery], SUM(NY) AS NY, SUM(IL) AS IL, SUM(GA) AS GA
from (select createdate [Date Processed],
stateprovince as [Province],
count(*) as [Total],
avg(datediff(day,createdate,t.eventdate)) as [AVG Delivery],
product
from recipient C left outer join
(select delivid, product, eventdesc, eventdate, eventcode
from deliverystatus
where delivid in (select max(deliv_id)
from deliverystatus
where eventcode = 'DELIVERED'
group by product)) as t ON c.product = t.product
where account = 3519 and consol <>'' and trknum <> '' and C.createdate between '2/4/2016' and '2/4/2016'
group by C.createdate, c.stateprovince, c.product
) as Q
pivot (
count(product)
for [Province] in (NY, IL, GA)
) as PVT
group by [Date Processed]
Related
So far, I have the following SQL Server 2005 query:
WITH D AS (
SELECT CONVERT(VARCHAR, '2020.11.01', 102) AS d_y_m, CAST('2020-11-01' AS DATETIME) AS dt
UNION ALL
SELECT CONVERT(VARCHAR, DATEADD(dd, 1, z.dt), 102) AS d_y_m, DATEADD(dd, 1, z.dt)
FROM D AS z
WHERE DATEADD(dd, 1, z.dt) <= '2020-11-30')
SELECT x.d_y_m, ISNULL(SUM(y.Total), 0) AS [Invoiced], ISNULL(SUM(FEI.Total), 0) AS [Paid] FROM D x
LEFT JOIN Invoices y ON CONVERT(VARCHAR, y.InvoiceDate, 102) = x.d_y_m
LEFT JOIN Payments AS FEI ON CONVERT(VARCHAR, FEI.PaymentDate, 102) = x.d_y_m
GROUP BY x.d_y_m
ORDER BY x.d_y_m OPTION (MAXRECURSION 0)
How do I add another column (RunningTotal) to the query which sums up the (Invoiced-Paid) result from the previous day to the one for today
Example:
d_y_m | Invoiced | Paid | RunningTotal
2020.11.01 | 24 | 5 | 19
2020.11.02 | 45 | 2 | 62
2020.11.03 | 10 | 20 | 52
2020.11.04 | 5 | 0 | 57
2020.11.05 | 0 | 10 | 47
Couple remarks on your current solution:
Do not use "random" table aliases. D for "dates" makes sense. y for "Invoices" does not. d_y_m does not match your date format either. Keep the table and column aliases meaningful.
Do not drag the date conversion through your entire solution. Work with date values as date types and convert the values once in the final select.
Do not group the sums of the invoiced and paid amounts in one query. If you have multiple invoices or payments on a single day, then the sums will be incorrect! See the "Extra" section at the bottom for an explanation.
Make it easy for us to help you. Next time, please provide sample data that we can copy-paste instead of having to invent our own.
SQL Server 2005 is officially unsupported as of April 12, 2016. Time to look for a new version!
Sample data
create table Invoices
(
InvoiceDate date,
Total money
);
insert into Invoices (InvoiceDate, Total) values
('2020-11-01', 20),
('2020-11-01', 4),
('2020-11-02', 40),
('2020-11-02', 5),
('2020-11-03', 10),
('2020-11-04', 3),
('2020-11-04', 2);
create table Payments
(
PaymentDate date,
Total money
);
insert into Payments (PaymentDate, Total) values
('2020-11-01', 5),
('2020-11-02', 2),
('2020-11-03', 10),
('2020-11-03', 10),
('2020-11-05', 10);
Solution
with DateRange as
(
select convert(date, '2020-11-01') as DateValue
union all
select dateadd(day, 1, dr.DateValue)
from DateRange dr
where dr.DateValue < '2020-11-30'
),
InvoicedTotal as
(
select dr.DateValue,
isnull(sum(i.Total), 0) as Invoiced
from DateRange dr
left join Invoices i
on i.InvoiceDate = dr.DateValue
group by dr.DateValue
),
PaidTotal as
(
select dr.DateValue,
isnull(sum(p.Total), 0) as Paid
from DateRange dr
left join Payments p
on p.PaymentDate = dr.DateValue
group by dr.DateValue
)
select convert(varchar(10), dr.DateValue, 102) as [YYYY.MM.DD],
it.Invoiced as [Invoiced],
sum(it.Invoiced) over(order by it.DateValue
rows between unbounded preceding and current row) as [CumInvoiced],
pt.Paid as [Paid],
sum(pt.Paid) over(order by pt.DateValue
rows between unbounded preceding and current row) as [CumPaid],
sum(it.Invoiced) over(order by it.DateValue
rows between unbounded preceding and current row) -
sum(pt.Paid) over(order by pt.DateValue
rows between unbounded preceding and current row) as [RunningTotal]
from DateRange dr
join InvoicedTotal it
on it.DateValue = dr.DateValue
join PaidTotal pt
on pt.DateValue = dr.DateValue
order by dr.DateValue;
Result
Only listing the first 10 of the 30 rows for November.
YYYY.MM.DD Invoiced CumInvoiced Paid CumPaid RunningTotal
---------- -------- ----------- ------- ------- ------------
2020.11.01 24.0000 24.0000 5.0000 5.0000 19.0000
2020.11.02 45.0000 69.0000 2.0000 7.0000 62.0000
2020.11.03 10.0000 79.0000 20.0000 27.0000 52.0000
2020.11.04 5.0000 84.0000 0.0000 27.0000 57.0000
2020.11.05 0.0000 84.0000 10.0000 37.0000 47.0000
2020.11.06 0.0000 84.0000 0.0000 37.0000 47.0000
2020.11.07 0.0000 84.0000 0.0000 37.0000 47.0000
2020.11.08 0.0000 84.0000 0.0000 37.0000 47.0000
2020.11.09 0.0000 84.0000 0.0000 37.0000 47.0000
2020.11.10 0.0000 84.0000 0.0000 37.0000 47.0000
Fiddle to see it in action.
Extra: why not to count both totals in one query.
Using the same sample data you can run this query to zoom in a particular date, here: 2020-11-01. On this date the sample data has 2 invoices and 1 payment.
with DateRange as
(
select '2020-11-01' as DateValue -- filtering data to explain
)
select dr.DateValue,
isnull(sum(i.Total), 0) as Invoiced,
isnull(sum(p.Total), 0) as Paid
from DateRange dr
left join Invoices i
on i.InvoiceDate = dr.DateValue
left join Payments p
on p.PaymentDate = dr.DateValue
group by dr.DateValue
order by dr.DateValue;
Just executing the joins would give you the result below. Because of the combined left join the payment row is listed twice!
dr.DateValue | i.Total | p.Total
------------ | ------- | -------
2020-11-01 | 20 | 5
2020-11-01 | 4 | 5 --> payment row got joined TWICE
Summing up those rows gives an invalid payment sum for that day.
group by dr.DateValue | sum(i.Total) | sum(p.Total)
--------------------- | ------------ | ------------
2020-11-01 | 24 | 10 --> last sum is WRONG !
Edit: SQL Server 2005 version with cross apply. But a SQL Server version update is still recommended!
with DateRange as
(
select convert(date, '2020-11-01') as DateValue
union all
select dateadd(day, 1, dr.DateValue)
from DateRange dr
where dr.DateValue < '2020-11-30'
),
InvoicedTotal as
(
select dr.DateValue,
isnull(sum(i.Total), 0) as Invoiced
from DateRange dr
left join Invoices i
on i.InvoiceDate = dr.DateValue
group by dr.DateValue
),
PaidTotal as
(
select dr.DateValue,
isnull(sum(p.Total), 0) as Paid
from DateRange dr
left join Payments p
on p.PaymentDate = dr.DateValue
group by dr.DateValue
)
select convert(varchar(10), dr.DateValue, 102) as [YYYY.MM.DD],
it1.Invoiced as [Invoiced],
it3.Invoiced as [CumInvoiced],
pt1.Paid as [Paid],
pt3.Paid as [CumPaid],
it3.Invoiced - pt3.Paid as [RunningTotal]
from DateRange dr
join InvoicedTotal it1
on it1.DateValue = dr.DateValue
join PaidTotal pt1
on pt1.DateValue = dr.DateValue
cross apply ( select sum(it2.Invoiced) as Invoiced
from InvoicedTotal it2
where it2.DateValue <= dr.DateValue ) it3
cross apply ( select sum(pt2.Paid) as Paid
from PaidTotal pt2
where pt2.DateValue <= dr.DateValue ) pt3
order by dr.DateValue;
Updated fiddle.
I have two tables
1) Fund details
ID Symbol
-------------------
1 ABC
2 XYZ
2) Fund Price data
Fund_id date Price
-------------------------------------------
1 2014-07-01 00:00:00.000 25.25
1 2014-07-02 00:00:00.000 25.45
......
2 2014-07-01 00:00:00.000 75.25
2 2014-07-02 00:00:00.000 75.42
.......
Now what I want to achieve is:
Here I am fetching the monthly data of a particular Fund as below:
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.Symbol = 'ABC'
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
Output:
Year Month Month Name Sales Count Symbol
-------------------------------------------
2014 4 April 21 ABC
2014 5 May 21 ABC
2014 6 June 21 ABC
2014 7 July 3 ABC
.......
Total Rows: 301
So here this is only for only particular fund which has returned 301 rows.
Now I want to get all the funds from the Fund details table which has rows less than given count ex 216 which I will pass as a parameter
Use Following query:
Declare #YourParameter int = 10
SELECT YEAR(date) [Year],
MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name],
COUNT(1) [Sales Count],
F.Symbol
FROM FundData FD
INNER JOIN FundDetails F on FD.ID = F.Fund_ID
Where FD.ID IN (SELECT z.Fund_ID
FROM FundDetails z
WHERE z.Fund_ID=FD.ID
GROUP BY z.Fund_ID, YEAR(z.date), MONTH(z.date)
HAVING COUNT(*) <= #YourParameter
)
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
I have fixed it:
Declare #YourParameter int = 110
WITH CTE AS
(
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.ID
IN (SELECT z.ID FROM FundDetails z)
GROUP BY F.Symbol, YEAR(date), MONTH(date), DATENAME(MONTH, date)
)
SELECT Symbol, COUNT(*) as cnt FROM CTE
GROUP BY Symbol
having COUNT(*) >= #YourParameter
How can i subtract two columns based on AccountGroupId 4 - AccountGroupId 5
I have data like :
ID Month Year AccountGroupName AccountGroupId Balance
1 February 2014 Expense 5 200
2 February 2014 Income 4 300
3 March 2014 Expense 5 250
4 March 2014 Income 4 200
Desired Result :
ID Month Year AccountGroupName AccountGroupId Balance
1 February 2014 Income 4 100
2 March 2014 Expense 5 -50
Query :
IF OBJECT_ID('tempdb..#temptbale') IS NOT NULL DROP TABLE #temptbale
IF OBJECT_ID('tempdb..#subTable') IS NOT NULL DROP TABLE #subTable
SELECT
(DATENAME(Month,JD.CreatedDateTime)) as [Month],
DATEPART(yyyy ,JD.CreatedDateTime) as [Year],
AG.AccountGroupName,
AT.AccountGroupID,
Sum(A.OpeningBalance) as Balance
into #temptbale
FROM AccountGroup AG
INNER JOIN AccountType AT ON AG.AccountGroupID=AT.AccountGroupID
Right join Account A on A.AccountTypeID = AT.AccountTypeID
Inner join JournalMasterDetail JD on JD.AccountID = A.AccountID
where AG.AccountGroupID > 3 and year(JD.CreatedDateTime) = year(getdate())
and datepart(dy, JD.CreatedDateTime) <= datepart(dy, getdate())
group by
A.AccountName,
JD.CreatedDateTime,
AG.AccountGroupName,
A.OpeningBalance,
AT.AccountGroupID
select ROW_NUMBER() OVER(ORDER BY [Month]) AS 'ID',[Month],[Year],AccountGroupName,AccountGroupID,SUM(Balance)as Balance
into #subTable
from #temptbale
group by
[Month],
AccountGroupName,
AccountGroupID,
[Year]
order by
[Month]
select * from #subTable
You can run this query
select t.Month,t.Year
,Case when tblExp.Balance > tblIncome.Balance then tblExp.AccountGroupName else tblIncome.AccountGroupName end as AccountGroupName
,Case when tblExp.Balance > tblIncome.Balance then tblExp. AccountGroupId else tblIncome. AccountGroupId end as AccountGroupId
,tblIncome.Balance - tblExp.Balance as Balance
from table t
inner join(select * from table where AccountGroupId = 4) as tblExp on tblExp.year = t.year and tblexp.Month = t.Month
inner join(select * from table where AccountGroupId = 5) as tblIncome on tblIncome.year = t.year and tblIncome.Month = t.Month
group by t.Month,t.Year
It's joining the Month and year with two derived tables as Income and expense
I have 5 Tables :
1- UserAccount : Has AccountNumber field
2- Total Amount : Has AccountNumber field
3- Total Withdrawal : Has AccountNumber field
4- Total Profit : Has AccountNumber field
5- Balance : Has AccountNumber field
I need to get the values of [Total Amount], [Total Withdrawal], [Total Profit] & [Balance] for each user in ONE table to be like:
AccountNumber Balance Total Amount Total Withdrawal Total Profit
----------------------------------------------------------------------------------
201 450 600 150 250
222 600 800 200 150
I used this query but the results isn't correct:
SELECT DISTINCT
dbo.useraccount.AccountNumber,
dbo.useraccount.FirstName,
dbo.useraccount.SecondName,
dbo.Balance.Balance,
sum(dbo.[Total Amount].DepositTotal) AS [Total Deposit],
Sum(dbo.[Total Profit].ProfitTotal) AS [Total Profit],
Sum(dbo.[Total Withdrawal].WithdrawalTotal) AS [Total Withdrawal]
FROM
dbo.useraccount ,
dbo.Balance ,
dbo.[Total Amount] ,
dbo.[Total Profit] ,
dbo.[Total Withdrawal]
WHERE
dbo.useraccount.AccountNumber = dbo.Balance.AccountNumber AND
dbo.useraccount.AccountNumber = dbo.[Total Amount].AccountNumber AND
dbo.useraccount.AccountNumber = dbo.[Total Profit].AccountNumber AND
dbo.useraccount.AccountNumber = dbo.[Total Withdrawal].AccountNumber
GROUP BY
dbo.useraccount.AccountNumber,
dbo.useraccount.FirstName,
dbo.useraccount.SecondName,
dbo.Balance.Balance
Any help please?
The results i am getting is something like this:
AccountNumber Balance Total Amount Total Withdrawal Total Profit
-----------------------------------------------------------------------
201 5316.52 291060.00 86328.20 51150.00
220 35000.00 2086400.00 648000.00 532800.00
221 12000.00 192000.00 44548.00 44548.00
222 8500.00 76500.00 12003.75 12003.75
224 4000.00 484000.00 120780.00 120780.00
226 2393.50 48000.00 5206.50 10736.00
When i run this query for [Total Profit] i get correct results:
SELECT DISTINCT
dbo.[Total Profit].AccountNumber,
Sum(dbo.[Total Profit].ProfitTotal) As [Total Deposit]
FROM
dbo.[Total Profit]
GROUP BY
dbo.[Total Profit].AccountNumber
Well, given that you haven't posted your tables definition, you can do this to avoid the duplication of rows:
SELECT UA.AccountNumber,
UA.FirstName,
UA.SecondName,
B.Balance,
TA.DepositTotal [Total Deposit],
TP.ProfitTotal [Total Profit],
TW.WithdrawalTotal [Total Withdrawal]
FROM dbo.useraccount UA
LEFT JOIN ( SELECT AccountNumber, SUM(Balance) Balance
FROM dbo.Balance
GROUP BY AccountNumber) B
ON UA.AccountNumber = B.AccountNumber
LEFT JOIN ( SELECT AccountNumber, SUM(DepositTotal) DepositTotal
FROM dbo.[Total Amount]
GROUP BY AccountNumber) TA
ON UA.AccountNumber = TA.AccountNumber
LEFT JOIN ( SELECT AccountNumber, SUM(ProfitTotal) ProfitTotal
FROM dbo.[Total Profit]
GROUP BY AccountNumber) TP
ON UA.AccountNumber = TP.AccountNumber
LEFT JOIN ( SELECT AccountNumber, SUM(WithdrawalTotal) WithdrawalTotal
FROM dbo.[Total Withdrawal]
GROUP BY AccountNumber) TW
ON UA.AccountNumber = TW.AccountNumber
Of course, you shouldn't need to do that aggregation for every table, only the ones that have multiple rows for each AccountNumber.
Table "tblCustomer":
Customer_id
created
field1
field2
cardno
1014
2010-05-25 12:51:59.547
Cell Phone
abc#lmn.com
1234567890
1015
2010-08-15 12:51:59.547
Email
abc#xyz.com
2345678891
Table "tbl_TransactionDishout":
Trnx_id
offerNo
TerminalID
Created
VirtualCard
1
1014
170924690436418
2010-05-25 12:51:59.547
1234567890
Expected Output:
Enrolled
Enrolled as Email
Enrolled as Text
Deals Redeemed
<First Date>
7
5
2
6
<Next Date>
9
3
6
14
I have two different queries which I need to combine into one.
First One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT )) AS Datetime) created,
COUNT(field1) Enrolled,
COUNT(CASE field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell
FROM tblCustomer as t
GROUP BY t.created
ORDER BY t.created DESC
Which Displays:
create
Enrolled
Enrolled_as_Email
Enrolled_as_Cell
2012-03-01 00:00:00.000
3
1
2
2012-02-29 00:00:00.000
1
0
1
Second One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT)) AS Datetime) created,
COUNT(*) [Deals_Redeemed]
FROM tbl_TransactionDishout t
LEFT JOIN tblCustomer c
ON t.VirtualCard = c.cardno
GROUP BY CAST(FLOOR(CAST(t.created AS FLOAT )) as Datetime)
ORDER BY t.created desc
Which Displays:
create
Deals_Redeemed
2012-03-02 00:00:00.000
1
2012-03-01 00:00:00.000
6
2012-02-28 00:00:00.000
1
2012-02-27 00:00:00.000
2
Now I want a record which contain date from both and should be combined into one.
But It's giving me the result of the date contained only in tblCustomer table..
How to get "Deals_redeemed"?
Note: relation between tbl_transaction and tblCustomer is having same cardno.
SELECT
CAST(t1.created AS DATE) created,
COUNT(t1.field1) Enrolled,
COUNT(CASE t1.field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE t1.field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell,
COUNT(t2.created) Deals_Redeemed
FROM tblCustomer AS t1
LEFT JOIN tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard
GROUP BY CAST(t1.created AS DATE)
ORDER BY CAST(t1.created AS DATE) DESC
Edit: Changed condition to cardno, and changed from FULL JOIN to LEFT JOIN.
You could Pivot():
select [create]
, sum([Email]+[Cell Phone]) as [Enrolled]
, max([Email]) as [Enrolled as Email]
, max([Cell Phone]) as [Enrolled as Cell Phone]
, max([Deal Redeemed]) as [Deals Redeemed]
from (
select [create]=created
, create1=created
, field1
from tblCustomer
union all
select [create]=created
, create1=created
, field1='Deal Redeemed'
from tbl_TransactionDishout
) p
pivot (
count(create1)
for field1 in ([Cell Phone],[Email],[Deal Redeemed])
) pv
group by [create]
order by [create]