Dynamic PIVOT over dynamic and multiple columns - sql

i'm trying to pivot dynamic pivot on multiple columns in SQL Server 2012
My table is as below
customer UnitNo invoiceNo invDate heads Amt periodFrmDT periodToDT
abc GF-3 C0000001 2015-11-01 Charge1 100 2015-11-01 2015-11-30
abc GF-3 C0000001 2015-11-01 Charge2 500 2015-11-10 2015-12-10
abc GF-3 C0000001 2015-11-01 charge3 600 2015-10-01 2015-10-30
and i want result like below
customer unitNo invoiceNo invDate Charge1 PeriodFrmDT periodToDT Charge2 PeriodFrmDT periodToDT Charge3 PeriodFrmDT periodToDT
abc GF-3 C0000001 2015-11-01 100 2015-11-01 2015-11-30 500 2015-11-10 2015-12-10 600 2015-10-01 2015-10-30
i have tried yet
select * from (
select c.Customer,unitNo, ih.invoiceNo
,bh.heads,it.Amt,periodFrmDT,PeriodToDT
from invHeader ih
inner join customer c on c.custID =ih.custID
inner join mstUnit mu on mu.unitID=ih.unitID
inner join invTran it on it.invID=ih.invHeaderID
inner join billingHeads bh on bh.BillHeadID=it.headID
)P
Pivot
(
max(amt)
for Head in([charge1],[charge2],[charge3])
) as pvt
Please help..

This will give you the table you have specified. The key thing here is that you must unpivot the amount, from date and to date for each charge first. This then allows you to repivot and see the values for all 3.
First I faked your data as follows:
declare #cte table (customer nvarchar(4)
, UnitNo nvarchar(4)
, invoiceNo nvarchar(8)
, invDate datetime
, heads nvarchar(8)
, Amt int
, periodFrmDT datetime
, periodToDT datetime)
insert into #cte ( customer, UnitNo, invoiceNo, invDate, heads, Amt, periodFrmDT, periodToDT)
values
('abc', 'GF-3', 'C0000001', '2015-11-01', 'Charge1', 100, '2015-11-01', '2015-11-30'),
('abc', 'GF-3', 'C0000001', '2015-11-01', 'Charge2', 500, '2015-11-10', '2015-12-10'),
('abc', 'GF-3', 'C0000001', '2015-11-01', 'charge3', 600, '2015-10-01', '2015-10-30');
Then I used the following query to get out the data as you requested:
with mycte as (select * from #cte
)
select * from
(
select customer, UnitNo ,invoiceNo ,invDate, heads + '_' + columnname as heads, value
from (select customer, UnitNo, invoiceNo, invDate, heads
, cast(Amt as nvarchar(10)) as Amt
, left(convert(nvarchar(10), periodFrmDT, 120), 10) as periodFrm
, left(convert(nvarchar(10), periodToDT, 120), 10) as periodTo
from mycte
) as t1
unpivot(value for columnname in (Amt, periodFrm ,periodTo)) as t2
) as t3 -- this table gives you your initial columns, then 2 more with the column headings for the next stage, and the values
-- columnname contains [Charge1_Amt], [Charge1_periodFrm], [Charge1_periodTo] etc
pivot (min(value) for heads in ( [Charge1_Amt], [Charge1_periodFrm], [Charge1_periodTo]
, [Charge2_Amt], [Charge2_periodFrm], [Charge2_periodTo]
, [charge3_Amt] , [charge3_periodFrm], [charge3_periodTo]
)
) as t4 -- And then we can re-pivot it all back up again.
To use the second query directly from you data, replace
with mycte as (select * from #cte
)
with
with mycte as (
-- This is the query with your base data
select c.Customer,unitNo, ih.invoiceNo, invDate ,bh.heads,it.Amt,periodFrmDT,PeriodToDT
from invHeader ih
inner join customer c on c.custID =ih.custID
inner join mstUnit mu on mu.unitID=ih.unitID
inner join invTran it on it.invID=ih.invHeaderID
inner join billingHeads bh on bh.BillHeadID=it.headID
)

Related

LEFT outer join returns returns duplicate rows even after adding distinct

Restricting the price change table to select a particular item
select * from price
where item = '13'
results of the query above
item Date_Changed New Old START_DATE end_DATE
13 01/11/2018 00:00 5.61 4.88 01/11/2018 00:00 30/11/2018 00:00
13 30/11/2018 00:00 2.84 5.61 01/11/2018 00:00 17/12/2018 00:00
13 17/12/2018 00:00 2.39 2.84 30/11/2018 00:00 17/12/2018 00:00
sales table
Date Item Qty Amount
05/07/2018 00:00 13 3 14.64
05/07/2018 00:00 13 3 14.64
04/07/2018 00:00 13 3 14.64
02/07/2018 00:00 13 1 4.88
02/07/2018 00:00 13 6 29.28
06/07/2018 00:00 13 7 34.16
03/07/2018 00:00 13 4 19.52
12/07/2018 00:00 13 2 9.76
10/08/2018 00:00 13 1 4.88
Sample code
SELECT distinct a.[Inv]
, (CASE
WHEN a.Date <= b.START_DATE THEN (b.Old * a.Qty)
WHEN a.Date between b.START_DATE and b.dt_end_DATE THEN (b.New * a.Qty)
ELSE 0
END) as calc_amount
,(a.[amount] - (CASE
WHEN a.Date <= b.START_DATE THEN (b.Old * a.Qty)
WHEN a.Date between b.START_DATE and b.end_DATE THEN (b.New * a.Qty)
ELSE 0
END)) as variance
[sales] a
left outer join price b
on a.[Item] = b.item
where b.item = '13'
The script then returns 27 rows instead of 9 rows. can someone assist on how i can improve my script to be more accurate
Use outer apply. I assume you want the most recent start date from price, so this looks like:
select s.*,
(case when s.date <= p.start_date
then p.Old * s.Qty
else p.New * s.Qty
end) as calc_amount
from sales s outer apply
(select top (1) p.*
from prices p
where p.item = s.item and
p.start_date <= s.date
order by p.date desc
) p
I am not sure if this is what you are looking for. but perhaps you can skip the join?
I created 2 sample data with the columns that you might need.
DECLARE #price table (item varchar(2),date_start date, new_price numeric(9,2))
Insert into #price (item , date_start,new_price)
values
( '13', '20190101', '1.00'),
( '13', '20190102', '1.01'),
( '13', '20190103', '1.02')
DECLARE #sales table (item varchar(2),date_sales date,qty int)
Insert into #sales (item , date_sales,qty)
values
( '13', '20190101', '5'),
( '13', '20190101', '2'),
( '13', '20190102', '5'),
( '13', '20190102', '2'),
( '13', '20190103', '5'),
( '13', '20190103', '2')
declare #item as varchar(2) = '13'
SELECT (select top (1) new_price from #price b where a.date_sales>=b.date_start and b.item = #item order by b.date_start desc ) * a.qty as 'new_price* qty'
from #sales a
where a.item = #item
I have not tested this in a table with a huge data set, so I also can't vouch for the speed of this query. I believe it would be better to have some kind of other ID to join the table
Your question is not clear... You added sample data, but I doubt this is correct...
Your price table is open to erronous data. It would be better to store just the price and a validFrom-date. In this case you can pick the price on a give date easily. Your format is open to overlapping periodes and there is no good reason to store the former price once again. That's why I ignore all fields you should not use...
Try this. I've changed the dates in a way to simulate validity periodes.
A mock-up scenario (please to this the next time for us):
CREATE TABLE priceMock(item INT, Date_Changed DATE, New DECIMAL(10,4), Old DECIMAL(10,4), [START_DATE] DATE, end_DATE DATE);
SET DATEFORMAT dmy;
INSERT INTO priceMock VALUES
(13,'01/11/2018 00:00',5.61,4.88,'01/07/2018 00:00','06/07/2018 00:00')
,(13,'30/11/2018 00:00',2.84,5.61,'07/07/2018 00:00','10/07/2018 00:00')
,(13,'17/12/2018 00:00',2.39,2.84,'11/07/2018 00:00','15/08/2018 00:00');
GO
CREATE TABLE salesMock ([Date] DATE, Item INT, Qty INT, Amount DECIMAL(10,4));
SET DATEFORMAT dmy;
INSERT INTO salesMock VALUES
('05/07/2018 00:00',13,3,14.64)
,('05/07/2018 00:00',13,3,14.64)
,('04/07/2018 00:00',13,3,14.64)
,('02/07/2018 00:00',13,1,4.88 )
,('02/07/2018 00:00',13,6,29.28)
,('06/07/2018 00:00',13,7,34.16)
,('03/07/2018 00:00',13,4,19.52)
,('10/07/2018 00:00',13,2,9.76 )
,('10/08/2018 00:00',13,1,4.88 );
GO
I'd add an inline-table-valued-function to get exactly one single line back.
CREATE FUNCTION dbo.GetPriceForItemOnDate(#item INT,#ValidOn DATE)
RETURNS TABLE
AS
RETURN
SELECT TOP 1 *
FROM priceMock
WHERE item=#item
AND [START_DATE] <= #ValidOn
ORDER BY [START_DATE] DESC
GO
--This query will combine your sales data with the price valid on the given date
SELECT s.[Date]
,s.Item
,s.Qty
,p.New AS CurrentPrice
,s.Qty * p.New AS ComputedAmount
FROM salesMock s
OUTER APPLY dbo.GetPriceForItemOnDate(s.item,s.[Date]) p
GO
--Clean up (carefull with real data)
DROP FUNCTION dbo.GetPriceForItemOnDate;
DROP TABLE priceMock;
DROP TABLE salesMock;
The idea in short:
The function will first filter to price lines for the given item. The second filter will cut the list and return just the prices for the given date and before the given date. As we sort this by the date in descending order we will get the latest price on top. By using TOP 1 we return just the one single line we want.
General remark: I use a validFrom-approach here. But you can turn this to the opposite and use a validTo-approach. The idea is the same.

Select hours from one table, but subtract hours from another where conditions exist?

using SQL Server and not sure if blanking or trying to do something I've never done before!
So to simplify, I'm doing a Select query for rostering. I have 2 tables:
[dbo].[LeaveBalances]
[PrimaryKey] [Employee] [LeaveType] [AsAtDate] [Balance]
1 100000 ANN 2017-10-23 10
2 100000 SIC 2017-10-23 16
[dbo].[P_R]
[PrimaryKey] [Employee] [ShiftDate] [LeaveType] [Hrs]
1 100000 2017-10-21 ANN 5
2 100000 2017-10-24 ANN 2
3 100000 2017-10-25 SIC 7
4 123456 2017-10-25 ANN 8
The result I want for the query to get the leave balances, net of anything taken after the [AsAtDate], is:
[Employee] [LeaveType] [AsAtDate] [Balance]
100000 ANN 2017-10-23 8
100000 SIC 2017-10-23 9
So the 2017-10-21 leave taken will be ignored because it's before the date, and the employee 123456 leave will be ignored because it's a different employee, but the other two will be subtracted from the corresponding leave type balances.
The query I've got so far is:
SELECT [Employee]
,[LeaveType]
,[AsAtDate]
,[Balance] -
(SELECT SUM([Hrs]) FROM [dbo].[P_R] WHERE [Employee] = 100000)
AS [Balance]
FROM [dbo].[LeaveBalances]
WHERE [Employee] = 100000
But obviously that's going so subtract all the [Hrs] values for employee 100000 from every leave type, regardless of [P_R] leave type or date. How do I incorporate in those other conditions?
Basically you want to select all LeaveBalances records and sum hours of P_R. You can do this in a subquery in the SELECT clause:
select
employee,
leavetype,
asatdate,
balance - (select sum(hrs) from dbo.p_r p where p.employee = b.employee
and p.leavetype = b.leavetype
and p.shiftdate > b.asatdate
) as balance
from dbo.leavebalances b
order by employee, leavetype;
Or move the subquery to your FROM clause with OUTER APPLY:
select
employee,
leavetype,
asatdate,
balance - coalesce(sums.total, 0) as balance
from leavebalances b
outer apply
(
select sum(hrs) as total
from p_r p
where p.employee = b.employee
and p.leavetype = b.leavetype
and p.shiftdate > b.asatdate
) sums
order by employee, leavetype;
This Can be achive by Using CTE
BEGIN TRAN
CREATE TABLE [dbo].[LeaveBalances]([ID] INT, [Employee] NVARCHAR(255), [LeaveType] NVARCHAR(6) , [AsAtDate] DATETIME, [Balance] INT)
CREATE TABLE[dbo].[P_R](ID INT,[Employee]NVARCHAR(255), [ShiftDate] DATETIME, [LeaveType] NVARCHAR(6) , [Hrs] INT)
INSERT INTO LeaveBalances
SELECT 1,'100000','ANN','2017-10-23',10 UNION ALL
SELECT 2,'100000','SIC','2017-10-23',16
INSERT INTO P_R
SELECT 1,'100000','2017-10-21','ANN',5 UNION ALL
SELECT 2,'100000','2017-10-24','ANN', 2 UNION ALL
SELECT 3 ,'100000','2017-10-25','SIC', 7 UNION ALL
SELECT 4,'123456','2017-10-25','ANN',8
;WITH CTE AS
(
SELECT DISTINCT a.Employee , a.LeaveType , a.AsAtDate , a.Balance
FROM LeaveBalances a INNER JOIN P_R P ON a.Employee=P.Employee
WHERE p.ShiftDate>a.AsAtDate
GROUP BY a.Employee , a.LeaveType , a.AsAtDate , a.Balance,p.Hrs
)
SELECT a.Employee , a.LeaveType , a.AsAtDate , a.Balance-b.Hrs Balance
FROM CTE a
INNER JOIN P_R b ON a.Employee=b.Employee AND a.LeaveType=b.LeaveType
WHERE b.ShiftDate > a.AsAtDate
ROLLBACK TRAN
I actually managed to come up with a solution that seems to work, no idea which method would be most efficient, though, but this one seems elegant enough:
SELECT [LB].[Employee]
,[LB].[LeaveType]
,[LB].[AsAtDate]
,[LB].[Balance] -
SUM(CASE WHEN [R].[LeaveType] = [LB].[LeaveType]
AND [R].[ShiftDate] > [LB].[AsAtDate]
THEN [R].[Hrs] ELSE 0 END) [Balance]
FROM [dbo].[LeaveBalances] [LB]
LEFT JOIN [dbo].[P_R] [R] ON [LB].[Employee] = [R].[Employee]
WHERE [LB].[Employee] = 100000 AND NOT [LB].[Entitlement] = 0
GROUP BY [LB].[LeaveType]
,[LB].[Employee]
,[LB].[AsAtDate]
GO
I managed to work out the following query. In the CTE below, I aggregate the number of sick and annual days spent by each employees after the AsAtDate specified in the LeaveBalances table. Note that I had to do a distinct select on LeaveBalances to isolate this cutoff date for each employee, implying that your data is not normalized.
WITH cte AS (
SELECT t1.[Employee], t1.[LeaveType], SUM(t1.[Hrs]) AS [Hrs]
FROM [dbo].[P_R] t1
INNER JOIN
(
SELECT DISTINCT [Employee], [AsAtDate]
FROM [dbo].[LeaveBalances]
) t2
ON t1.[Employee] = t2.[Employee]
WHERE t1.[ShiftDate] > t2.[AsAtDate]
GROUP BY t1.[Employee], t1.[LeaveType]
)
SELECT
t1.[Employee], t1.[LeaveType], t1.[AsAtDate],
t1.[Balance] - COALESCE(t2.[Hrs], 0) AS [Balance]
FROM [dbo].[LeaveBalances] t1
LEFT JOIN cte t2
ON t1.[Employee] = t2.[Employee] AND
t1.[LeaveType] = t2.[LeaveType];
Output:
Demo here:
Rextester
CREATE TABLE #LeaveBalances([ID] INT, [Employee] NVARCHAR(255), [LeaveType] NVARCHAR(6) , [AsAtDate] DATETIME, [Balance] INT)
CREATE TABLE #P_R(ID INT,[Employee]NVARCHAR(255), [ShiftDate] DATETIME, [LeaveType] NVARCHAR(6) , [Hrs] INT)
INSERT INTO #LeaveBalances
SELECT 1,'100000','ANN','2017-10-23',10 UNION ALL
SELECT 2,'100000','SIC','2017-10-23',16
INSERT INTO #P_R
SELECT 1,'100000','2017-10-21','ANN',5 UNION ALL
SELECT 2,'100000','2017-10-24','ANN', 2 UNION ALL
SELECT 3 ,'100000','2017-10-25','SIC', 7 UNION ALL
SELECT 4,'123456','2017-10-25','ANN',8;
;WITH CTE AS (
SELECT LBS.Employee,LBS.LeaveType,LBS.AsAtDate,LBS.Balance,#P_R.Hrs,
ROW_NUMBER()OVER(
PARTITION BY LBS.Employee,LBS.LeaveType
ORDER BY LBS.LeaveType,#P_R.ShiftDate DESC
) AS RN
FROM #LeaveBalances AS LBS INNER JOIN #P_R
ON (LBS.Employee=#P_R.Employee)
AND
(LBS.LeaveType=#P_R.LeaveType)
)
SELECT Employee,LeaveType,CAST(AsAtDate AS DATE) AS AsAtDate,
SUM(Balance-Hrs)over(PARTITION BY Employee,LeaveType ORDER BY LeaveType) AS Balance
from CTE WHERE RN=1;
------------------------------------------
Employee LeaveType AsAtDate Balance
---------------------------------------------
100000 ANN 2017-10-23 8
100000 SIC 2017-10-23 9

Any one help me to solve this i try my best but did not solve this?

ItemName Price CreatedDateTime
New Card 50.00 2014-05-26 19:17:09.987
Recharge 110.00 2014-05-26 19:17:12.427
Promo 90.00 2014-05-27 16:17:12.427
Membership 70.00 2014-05-27 16:17:12.427
New Card 50.00 2014-05-26 19:20:09.987
Out Put : Need a query which Sum the sale of Current hour and
sale of item which have maximum sale in that hour in breakdownofSale
Column.
Hour SaleAmount BreakDownOfSale
19 210 Recharge
16 160 Promo
This should do it
create table #t
(
ItemName varchar(50),
Price decimal(18,2),
CreatedDateTime datetime
);
set dateformat ymd;
insert into #t values('New Card', 50.00, '2014-05-26 19:17:09.987');
insert into #t values('Recharge', 110.00, '2014-05-26 19:17:12.427');
insert into #t values('Promo', 90.00, '2014-05-27 16:17:12.427');
insert into #t values('Membership', 70.00, '2014-05-27 16:17:12.427');
insert into #t values('New Card', 50.00, '2014-05-26 19:20:09.987');
with cte as
(
select datepart(hh, CreatedDateTime) as [Hour],
ItemName,
Price,
sum(Price) over (partition by datepart(hh, CreatedDateTime)) SaleAmount,
ROW_NUMBER() over (partition by datepart(hh, CreatedDateTime) order by Price desc) rn
from #t
)
select Hour,
SaleAmount,
ItemName
from cte
where rn = 1
Though i am not clear with the question, based on your desired output, you may use the query as below.
SELECT DATEPART(HOUR,CreatedDateTime) AS Hour, sum(Price) AS Price, ItemName AS BreakDownOfSale from TableName WHERE BY ItemName,DATEPART(HOUR,CreatedDateTime)
Replace table name and column name with the actual one.
Hope this helps!
Here is the sample query.
You can use SQL Server Windows functions to get the result you need.
DECLARE #Table TABLE
(
ItemName NVARCHAR(40),
Price DECIMAL(10,2),
CreatedDatetime DATETIME
)
-- Fill table.
INSERT INTO #Table
( ItemName, Price, CreatedDatetime )
VALUES
( N'New Card' , 50.00 , '2014-05-26 19:17:09.987' ),
( N'Recharge' , 110.00 , '2014-05-26 19:17:12.427' ) ,
( N'Promo' , 90.00 , '2014-05-27 16:17:12.427' ) ,
( N'Membership' , 70.00 , '2014-05-27 16:17:12.427' ) ,
( N'New Card' , 50.00 , '2014-05-26 19:20:09.987' )
-- Check record(s).
SELECT * FROM #Table
-- Get record(s) in required way.
;WITH T1 AS
(
SELECT
DATEPART(HOUR, T.CreatedDatetime) AS Hour,
CONVERT(DATE, T.CreatedDatetime) AS Date,
T.ItemName AS BreakDownOfSales,
-- Date and hour both will give unique record(s)
SUM(Price) OVER (PARTITION BY CONVERT(DATE, T.CreatedDatetime), DATEPART(HOUR, CreatedDateTime)) AS SaleAmount,
ROW_NUMBER() OVER(PARTITION BY CONVERT(DATE, T.CreatedDatetime), DATEPART(HOUR, T.CreatedDatetime) ORDER BY T.Price DESC) AS RN
FROM
#Table T
)
SELECT
T1.Date ,
T1.Hour ,
T1.SaleAmount,
T1.BreakDownOfSales
FROM
T1
WHERE T1. RN = 1
ORDER BY
T1.Hour
Check this simple solution, Please convert it to SQL Server Query.
This will give you perfect result even if you have multiple date data.
SELECT HOUR(CreatedDateTime), SUM(Price),
(SELECT itemname FROM t it WHERE HOUR(ot.CreatedDateTime) = HOUR(it.CreatedDateTime) AND
DATE(ot.CreatedDateTime) = DATE(it.CreatedDateTime)
GROUP BY itemname
ORDER BY price DESC
LIMIT 1
) g
FROM t ot
GROUP BY HOUR(CreatedDateTime);

How to group value within a certain date range or every certain days in SQL server

For example table would be:
Customer OrderDate OrderAmt
-------- ---------- ---------
A1 20140101 920.00
A2 20140111 301.00
A2 20140123 530.00
A1 20140109 800.00
A3 20140110 500.00
A1 20140115 783.00
A3 20140217 500.00
A1 20140219 1650.00
A1 20140225 780.00
...
A3 20140901 637.00
I want to group them and calculate the sum(OrderAmt) within every 20 days and group by customer start from 20140101.
For what it's worth, you can accomplish what you describe with a pretty simple DATEDIFF() / GROUP BY operation, as below: whether or not that is actually what you want might be another question. I suspect that the DateBucket calculation might actually be something else ...
CREATE TABLE #tmpCustomer (Customer VARCHAR(2), OrderDate VARCHAR(10), OrderAmt DECIMAL(6,2))
INSERT INTO #tmpCustomer (Customer, OrderDate, OrderAmt)
SELECT 'A1',20140101, 920.00 UNION
SELECT 'A2',20140111, 301.00 UNION
SELECT 'A2',20140123, 530.00 UNION
SELECT 'A1',20140109, 800.00 UNION
SELECT 'A3',20140110, 500.00 UNION
SELECT 'A1',20140115, 783.00 UNION
SELECT 'A3',20140217, 500.00 UNION
SELECT 'A1',20140219, 1650.00 UNION
SELECT 'A1',20140225, 780.00 UNION
SELECT 'A3',20140901, 637.00
SELECT
Customer,
(DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1 AS DateBucket,
SUM(OrderAmt) SumOrderAmt
FROM #tmpCustomer
GROUP BY Customer, (DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1
ORDER BY Customer, DateBucket
You need to do two things:
(1) Create some sort of guide hold the '20 day groups' information. A Recursive CTE does this pretty well, and
(2) Recast that varchar date as an actual date for comparison purposes.
Then it's just joining the order data into that daterange grouping and summing the order amounts.
-------------------------
-- Here i'm just recreating your example
-------------------------
DECLARE #customerOrder TABLE (Customer varchar(2), OrderDate varchar(8), OrderAmt decimal(8,2))
INSERT INTO #customerOrder (Customer, OrderDate, OrderAmt)
VALUES
('A1', '20140101', 920.00),
('A2', '20140111', 301.00),
('A2', '20140123', 530.00),
('A1', '20140109', 800.00),
('A3', '20140110', 500.00),
('A1', '20140115', 783.00),
('A3', '20140217', 500.00),
('A1', '20140219', 1650.00),
('A1', '20140225', 780.00),
('A3', '20140901', 637.00)
-------------------------
-- Set up a table that lists off 20 day periods starting from 1/1/2014
-------------------------
DECLARE #startDate datetime, #endDate datetime;
SET #startDate = {d N'2014-01-01'};
SET #endDate = {d N'2014-12-31'};
WITH [dates] ([Sequence], [startDate], [maxExcludedDate]) AS
(SELECT 1 AS [Sequence]
,#startDate AS [startDate]
,DATEADD(d, 20, #startDate) AS [maxExcludedDate]
UNION ALL
SELECT Sequence + 1 AS Sequence
,DATEADD(d, 20, [startDate]) AS [startDate]
,DATEADD(d, 40, [startDate]) AS [maxExcludedDate]
FROM [dates]
WHERE [startDate] < #endDate
)
, dateFrame AS
(
SELECT
[startDate]
,[maxExcludedDate]
FROM [dates]
)
-------------------------
-- Set up a table that holds the orderDates as actual dates
-------------------------
, castData AS
(
SELECT
cast(orderdate as datetime) castDate
,OrderAmt
FROM #customerOrder
)
-------------------------
-- JOIN and sum.
-------------------------
SELECT
[startDate]
, Sum(OrderAmt) perodAmt
FROM
dateFrame df
left join castData cd
on cd.castDate >= df.startDate
and cd.castDate < df.maxExcludedDate
GROUP BY
[startDate]
ORDER by
[startDate]
Assuming that the OrderDate is a numeric field (not varchar). I'm also assuming that you don't need to go much more than a year in the future. If you want the gaps shown, keep the left join, if you don't want the gaps, then make it an inner join. (You can also make the hardcoded date a variable of where to start, I just kept it as the 20140101 that you mentioned.
with Numbers as
(Select 0 as Num
UNION ALL
Select Num+1
FROM Numbers
WHERE Num+1<= 20
)
, DateList AS
(Select Year(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) * 10000+Month(DateAdd(dd,20*(Num), Cast('2014-01-01' as date)))*100+Day(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) Groupingdatemin
, Year(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*10000+ MONTH(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*100+DAY(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date))) Groupingdatemax
from Numbers
)
select Customer, sum(orderamt), Groupingdatemin, Groupingdatemax from DateLIst d LEFT JOIN
<yourtable> t on t.orderdate between d.Groupingdatemin and d.Groupingdatemax
group by customer, Groupingdatemin, Groupingdatemax

sql query get max date from different table

ok, I have a TankID and a UnitNumber in one table and an ExpiredDate in another table, but that table has multiple expired dates for the same tankID, I just want the max(ExpiredDate).
TankID UnitNumber ExpiredDate
20666 107 2009-08-31 00:00:00
20666 107 2010-08-31 00:00:00
20666 107 2011-08-31 00:00:00
20666 107 2012-08-31 00:00:00
20666 107 NULL
Now I just want to return
20666 107 2012-08-31
I tried to do this:
select tanks.TankID, tanks.UnitNumber, MAX(Table2.ExpireDate)
from Tanks
join Table2 on Tanks.TankID = Table2.TankID
where CompanyID = '1111'
and Tanks.TankID = '22222'
order by Tanks.TankID
That obviously doesn't work, does anybody know how to do this? Thanks
try
SELECT tanks.tankId, tanks.unitNumber, (SELECT MAX(table2.ExpiraDate) FROM table2 WHERE table2.tankID = tanks.tankID) AS max_expire_date
FROM tanks
where CompanyID = '1111'
and Tanks.TankID = '22222'
order by Tanks.TankID
select tanks.TankID, tanks.UnitNumber,
(select MAX(Table2.ExpireDate) from Table2 where table2.TankID = Tanks.TankID) ExpireDate
from Tanks
where CompanyID = '1111'
and Tanks.TankID = '22222'
order by Tanks.TankID
or
select tanks.TankID, tanks.UnitNumber, maxExpireDate.ExpireDate
from Tanks join
(
select TankID, MAX(Table2.ExpireDate) ExpireDate
from Table2
group by TankID
) maxExpireDate
on Tanks.TankID = maxExpireDate.TankID
where CompanyID = '1111'
and Tanks.TankID = '22222'
order by Tanks.TankID
I'm pasting two ways to do this. Both queries do the same thing in a different way. I set up a table variable with mock data so you can test this on a local database (or anywhere) and see that it works.
DECLARE #Tanks TABLE
(
CompanyId INT NOT NULL,
TankId INT NOT NULL,
UnitNumber INT NOT NULL
)
DECLARE #Expirations TABLE
(
TankId INT NOT NULL,
ExpiredDate DATETIME NULL
)
INSERT #Tanks
(
CompanyId
, TankId
, UnitNumber
)
VALUES
(1111, 22222, 107)
INSERT #Expirations
(
TankId
, ExpiredDate
)
VALUES
(22222, '2009-08-31 00:00:00')
, (22222, '2010-08-31 00:00:00')
, (22222, '2011-08-31 00:00:00')
, (22222, '2012-08-31 00:00:00')
, (22222, NULL)
SELECT
Tanks.TankId
, Tanks.UnitNumber
, Expiration.MaxExpiredDate
FROM #Tanks Tanks
CROSS APPLY
(
SELECT MAX(E.ExpiredDate) MaxExpiredDate FROM #Expirations E WHERE E.TankId = Tanks.TankId
) Expiration
WHERE Tanks.CompanyId = 1111 AND Tanks.TankId = 22222
SELECT
Tanks.TankId
, Tanks.UnitNumber
, MAX(Expirations.ExpiredDate) ExpiredDate
FROM #Tanks Tanks
LEFT JOIN #Expirations Expirations
ON Expirations.TankId = Tanks.TankId
WHERE Tanks.CompanyId = 1111 AND Tanks.TankId = 22222
GROUP BY Tanks.TankId, Tanks.UnitNumber