I'm going to post my query at the end of this post here, but just exposition is required first. Please ignore the column names and table names but I have syntax errors in two spots. When I put this query with my CTE it tells me I have to first 'terminate the previous statement with a ;' Then I go onto alias a column name in the CTE and then it says 'The multi-part identifier "E.ActiveAGVs" could not be bound.'
I hope that I am explaining my problem well enough. If anyone can see what I'm trying to do and let me know if it will work or correct my syntax errors, I would really appreciate it.
Select A.move_hour as 'Hour',
isnull(B.move_count,0) as 'Current_Count',
isnull(C.move_count,0) as '1_Day_Previous',
isnull(D.move_count,0) as '2_Day_Previous',
ISNULL (E.ActiveAGVs,0) as 'Active AGV''s'
--^ Error right here
from
(select distinct(DATEPART(HH, Move_History.Move_Dt)) as move_hour
from Move_History
where Plant_Id = 1 and Building_Id = 1) as A
left outer join
(select datepart(HH,Move_History.Move_Dt) as move_hour,
Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt) as B on A.move_hour = B.move_hour
left outer join
(select datepart(HH,Move_History.Move_Dt) as move_hour, Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt) as C on A.move_hour = C.move_hour
left outer join
(select datepart(HH,Move_History.Move_Dt) as move_hour, Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt) as D on A.move_hour = D.move_hour;
with const as (
select cast(cast(getdate() as date) as datetime) as midnight
),
allhours as (
select 0 as m_hour, midnight as timestart, dateadd(hour, 1, midnight) as timeend from const union all
...
select 23 as m_hour, dateadd(hour, 23, midnight) as timestart, dateadd(hour, 24, midnight) as timeend from const
)
(select ah.m_hour,
(sum(datediff(SECOND, timestart), ah.timeend else dt.End_Dt end))
/ 18000.0) * 5 as ActiveAGVs
from allhours as ah
left outer join AGV_Report as dt
on ah.timestart< coalesce(dt.End_dt, getdate()) and
ah.timeend >= dt.Begin_Dt
Group by datepart(SECOND,ah.hour), ah.timestart) as E on A.move_hour = E.move_hour
--^ 'Incorrect syntax near "as"'
where A.move_hour is not null
order by ah.m_hour asc
All CTEs that you need to define for a statement, must go at the beginning of the statement. Even though the CTEs are going to be used only in one of the subqueries, the syntax still requires them to be placed at the beginning of the entire statement, not at the beginning of the particular subquery where they are actually referenced.
Therefore, your statement should probably look something like this:
; -- required if there are statements preceding
with const as (
select cast(cast(getdate() as date) as datetime) as midnight
),
allhours as (
select
0 as m_hour,
midnight as timestart,
dateadd(hour, 1, midnight) as timeend
from const
union all
...
select
23 as m_hour,
dateadd(hour, 23, midnight) as timestart,
dateadd(hour, 24, midnight) as timeend
from const
)
Select A.move_hour as 'Hour',
isnull(B.move_count,0) as 'Current_Count',
isnull(C.move_count,0) as '1_Day_Previous',
isnull(D.move_count,0) as '2_Day_Previous',
ISNULL (E.ActiveAGVs,0) as 'Active AGV''s'
from
(
select distinct
DATEPART(HH, Move_History.Move_Dt) as move_hour
from Move_History
where Plant_Id = 1 and Building_Id = 1
) as A
left outer join
(
select
datepart(HH,Move_History.Move_Dt) as move_hour,
Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt
) as B on A.move_hour = B.move_hour
left outer join
(
select
datepart(HH,Move_History.Move_Dt) as move_hour,
Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt
) as C on A.move_hour = C.move_hour
left outer join
(
select
datepart(HH,Move_History.Move_Dt) as move_hour,
Move_History.Move_Cnt as move_count
from Move_History
Group by datepart(HH,Move_History.Move_Dt), Move_Cnt
) as D on A.move_hour = D.move_hour
left outer join -- assuming...
(
select
ah.m_hour,
(sum(datediff(SECOND, timestart), ah.timeend else dt.End_Dt end))
/ 18000.0) * 5 as ActiveAGVs
from allhours as ah
left outer join AGV_Report as dt
on ah.timestart < coalesce(dt.End_dt, getdate())
and ah.timeend >= dt.Begin_Dt
Group by datepart(SECOND,ah.hour), ah.timestart
) as E on A.move_hour = E.move_hour
where A.move_hour is not null
order by ah.m_hour asc
A common table expression (CTE) must be separated from any prior statement by a semicolon (;). If no statements precede the with then there is no need for a semicolon.
You can have multiple CTEs within a single with. An example follows:
with
-- Counting numbers.
Numbers as (
select 1 as Number
union all
select Numbers.Number + 1
from Numbers
where Number < 10 ),
-- Squares of counting numbers.
Squares as (
select Number, Number * Number as Square
from Numbers )
-- Result.
select Number, Square
from Squares
Like the rest of the people trying to help, I have no idea of what your SQL is trying to do.
Related
I did some digging within stackoverflow for a solution and nothing quite matched what I was after (I don't think).
My goal is to combine two queries that will return 3 columns [date, OUT, IN] as output.
On their own, the two queries return the correct output.
1st SELECT query for OUT returns
[03/01, 4],[03/02, 10],[03/03, 21],[03/01, 4]
2nd SELECT query for IN returns
[03/01, 4],[03/03, 25]
Using WITH to combine the two queries, two different ways, the outputs are identical.
[03/01, 4, 4], [03/03, 21, 25] -> OUT as inner query
[03/01, 4, 4], [03/03, 21, 25] -> IN as inner query
As can be seen, because nothing came IN on the 2nd and 4th of March, an empty row is returned for those dates. I believe the correct way to use the WITH query is to have the OUT as the inner query so the 2nd and 4th are part of the recursion in the outer query.
Pasted below is a simplified version of what the WITH query looks like. On its own, the inner query returns a count for each day of March. For some reason, the outer query does not return 0 when it does not have a count for the date in question (2nd and 4th).
Anyone have advice on how to solve this one? Could I be using COALESCE incorrectly?
WITH first_query (the_date, out) AS
(
SELECT DISTINCT ON(to_char(t1.date, 'dd')) to_char(t1.out_date, 'dd') AS out_date2, count(to_char(t1.out_date, 'dd')) AS out
FROM table_out AS t1
WHERE to_char(t1.out_date,'yyyy') = to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month', CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
)
SELECT fq.the_date AS day_of_month, fq.out, COALESCE( ( SELECT COUNT(to_char(t1.in_date, 'DD')) ), 0) AS in
FROM first_query fq, table_in t1
WHERE to_char(t1.in_date,'yyyy') = to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.in_date,'MM') = to_char(date_trunc('month', CURRENT_DATE), 'MM')
AND to_char(t1.in_date,'dd') = fq.the_date
GROUP BY day_of_month, fq.out
ORDER BY day_of_month ASC
The answer ended up requiring CAST and LEFT JOIN as Jeremy suggested. The timestamps made this harder than it had to be.
SELECT CAST(t1.out_date AS Date) AS date2, count(DISTINCT
t1.id) out, count(DISTINCT t2.id) AS in
FROM table_out as t1
LEFT JOIN table_in AS t2 ON CAST(t1.out_date AS Date) =
CAST(t2.in_date AS Date)
WHERE to_char(t1.out_date,'yyyy') =
to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month',
CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
The answer ended up requiring CAST and LEFT JOIN as Jeremy suggested. The timestamps made this harder than it had to be.
SELECT CAST(t1.out_date AS Date) AS date2, count(DISTINCT
t1.id) out, count(DISTINCT t2.id) AS in
FROM table_out as t1
LEFT JOIN table_in AS t2 ON CAST(t1.out_date AS Date) =
CAST(t2.in_date AS Date)
WHERE to_char(t1.out_date,'yyyy') =
to_char(date_trunc('year', CURRENT_DATE), 'YYYY')
AND to_char(t1.out_date,'MM') = to_char(date_trunc('month',
CURRENT_DATE), 'MM')
AND t1.out_id = 14
GROUP BY out_date2
I have a table that looks like this:
A slowly changing dimension type 2, according to Kimball.
Key is just a surrogate key, a key to make rows unique.
As you can see there are three rows for product A.
Timelines for this product are ok. During time the description of the product changes.
From 1-1-2020 up until 4-1-2020 the description of this product was ProdA1.
From 5-1-2020 up until 12-2-2020 the description of this product was ProdA2 etc.
If you look at product B, you see there are gaps in the timeline.
We use DB2 V12 z/Os. How can I check if there are gaps in the timelines for each and every product?
Tried this, but doesn't work
with selectie (key, tel) as
(select product, count(*)
from PROD_TAB
group by product
having count(*) > 1)
Select * from
PROD_TAB A
inner join selectie B
on A.product = B.product
Where not exists
(SELECT 1 from PROD_TAB C
WHERE A.product = C.product
AND A.END_DATE + 1 DAY = C.START_DATE
)
Does anyone know the answer?
The following query returns all gaps for all products.
The idea is to enumerate (RN column) all periods inside each product by START_DATE and join each record with its next period record.
WITH
/*
MYTAB (PRODUCT, DESCRIPTION, START_DATE, END_DATE) AS
(
SELECT 'A', 'ProdA1', DATE('2020-01-01'), DATE('2020-01-04') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'A', 'ProdA2', DATE('2020-01-05'), DATE('2020-02-12') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'A', 'ProdA3', DATE('2020-02-13'), DATE('2020-12-31') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'B', 'ProdB1', DATE('2020-01-05'), DATE('2020-01-09') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'B', 'ProdB2', DATE('2020-01-12'), DATE('2020-03-14') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'B', 'ProdB3', DATE('2020-03-15'), DATE('2020-04-18') FROM SYSIBM.SYSDUMMY1
UNION ALL SELECT 'B', 'ProdB4', DATE('2020-04-16'), DATE('2020-05-03') FROM SYSIBM.SYSDUMMY1
)
,
*/
MYTAB_ENUM AS
(
SELECT
T.*
, ROWNUMBER() OVER (PARTITION BY PRODUCT ORDER BY START_DATE) RN
FROM MYTAB T
)
SELECT A.PRODUCT, A.END_DATE + 1 START_DT, B.START_DATE - 1 END_DT
FROM MYTAB_ENUM A
JOIN MYTAB_ENUM B ON B.PRODUCT = A.PRODUCT AND B.RN = A.RN + 1
WHERE A.END_DATE + 1 <> B.START_DATE
AND A.END_DATE < B.START_DATE;
The result is:
|PRODUCT|START_DT |END_DT |
|-------|----------|----------|
|B |2020-01-10|2020-01-11|
May be more efficient way:
WITH MYTAB2 AS
(
SELECT
T.*
, LAG(END_DATE) OVER (PARTITION BY PRODUCT ORDER BY START_DATE) END_DATE_PREV
FROM MYTAB T
)
SELECT PRODUCT, END_DATE_PREV + 1 START_DATE, START_DATE - 1 END_DATE
FROM MYTAB2
WHERE END_DATE_PREV + 1 <> START_DATE
AND END_DATE_PREV < START_DATE;
Thnx Mark, will try this one of these days.
Never heard of LAG in DB2 V12 for z/Os
Will read about it
Thnx
SELECT
CAST(c.DT AS DATE) AS 'Date'
, COUNT(p.PatternID) AS 'Count'
FROM CalendarMain c
LEFT OUTER JOIN Pattern p
ON c.DT = p.PatternDate
INNER JOIN Result r
ON p.PatternID = r.PatternID
INNER JOIN Detail d
ON p.PatternID = d.PatternID
WHERE r.Type = 7
AND d.Panel = 501
AND CAST(c.DT AS DATE)
BETWEEN '20190101' AND '20190201'
GROUP BY CAST(c.DT AS DATE)
ORDER BY CAST(c.DT AS DATE)
The query above isn't working for me. It still skips days where the COUNT is NULL for it's c.DT.
c.DT and p.PatternDate are both time DateTime, although c.DT can't be NULL. It is actually the PK for the table. It is populated as DateTimes for every single day from 2015 to 2049, so the records for those days exist.
Another weird thing I noticed is that nothing returns at all when I join C.DT = p.PatternDate without a CAST or CONVERT to a Date style. Not sure why when they are both DateTimes.
There are a few things to talk about here. At this stage it's not clear what you're actually trying to count. If it's the number of "patterns" per day for the month of Jan 2019, then:
Your BETWEEN will also count any activity occurring on 1 Feb,
It looks like one pattern could have multiple results, potentially causing a miscount
It looks like one pattern could have multiple details, potentially causing a miscount
If one pattern has say 3 eligible results, and also 4 details, you'll get the cross product of them. Your count will be 12.
I'm going to assume:
you only want the distinct number of patterns, regardless of the number of details and results.
You only want January's activity
--Set up some dummy data
DROP TABLE IF EXISTS #CalendarMain
SELECT cast('20190101' as datetime) as DT
INTO #CalendarMain
UNION ALL SELECT '20190102' as DT
UNION ALL SELECT '20190103' as DT
UNION ALL SELECT '20190104' as DT
UNION ALL SELECT '20190105' as DT --etc etc
;
DROP TABLE IF EXISTS #Pattern
SELECT cast('1'as int) as PatternID
,cast('20190101 13:00' as datetime) as PatternDate
INTO #Pattern
UNION ALL SELECT 2,'20190101 14:00'
UNION ALL SELECT 3,'20190101 15:00'
UNION ALL SELECT 4,'20190104 11:00'
UNION ALL SELECT 5,'20190104 14:00'
;
DROP TABLE IF EXISTS #Result
SELECT cast(100 as int) as ResultID
,cast(1 as int) as PatternID
,cast(7 as int) as [Type]
INTO #Result
UNION ALL SELECT 101,1,7
UNION ALL SELECT 102,1,8
UNION ALL SELECT 103,1,9
UNION ALL SELECT 104,2,8
UNION ALL SELECT 105,2,7
UNION ALL SELECT 106,3,7
UNION ALL SELECT 107,3,8
UNION ALL SELECT 108,4,7
UNION ALL SELECT 109,5,7
UNION ALL SELECT 110,5,8
;
DROP TABLE IF EXISTS #Detail
SELECT cast(201 as int) as DetailID
,cast(1 as int) as PatternID
,cast(501 as int) as Panel
INTO #Detail
UNION ALL SELECT 202,1,502
UNION ALL SELECT 203,1,503
UNION ALL SELECT 204,1,502
UNION ALL SELECT 205,1,502
UNION ALL SELECT 206,1,502
UNION ALL SELECT 207,2,502
UNION ALL SELECT 208,2,503
UNION ALL SELECT 209,2,502
UNION ALL SELECT 210,4,502
UNION ALL SELECT 211,4,501
;
-- create some variables
DECLARE #start_date as date = '20190101';
DECLARE #end_date as date = '20190201'; --I assume this is an exclusive end date
SELECT cal.DT
,isnull(patterns.[count],0) as [Count]
FROM #CalendarMain cal
LEFT JOIN ( SELECT cast(p.PatternDate as date) as PatternDate
,COUNT(DISTINCT p.PatternID) as [Count]
FROM #Pattern p
JOIN #Result r ON p.PatternID = r.PatternID
JOIN #Detail d ON p.PatternID = d.PatternID
WHERE r.[Type] = 7
and d.Panel = 501
GROUP BY cast(p.PatternDate as date)
) patterns ON cal.DT = patterns.patternDate
WHERE cal.DT >= #start_date
and cal.DT < #end_date --Your code would have included 1 Feb, which I assume was unintentional.
ORDER BY cal.DT
;
I have 3 tables:
with current_exclusive as(
select id_station, area_type,
count(*) as total_entries
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date <= '2017-12-30'
group by id_station, area_type
), current_table as(
select id_station, area_type,
sum(total_time) filter (where previous_status = 1) as total_time
from c1169.data_table
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
), current_cashier as(
select id_station, area_type,
sum(1) as total_transactions
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
)
select *
from current_exclusive
full join current_table on current_exclusive.id_station = current_table.id_station and current_exclusive.area_type = current_table.area_type
full join current_cashier on current_exclusive.id_station = current_cashier.id_station and current_exclusive.area_type = current_cashier.area_type
and the result is:
but my expected result is:
Are there any way to select * and show the expected result? Because when I do full join then id_station and area_type can be null in some tables, so it very hard to choose which column is not null.
Like: select case id_station is not null then id_station else id_station1 end, but I have up to 10 tables so can not do in select case
Use USING, per the documentation:
USING ( join_column [, ...] )
A clause of the form USING ( a, b, ... ) is shorthand for ON left_table.a = right_table.a AND left_table.b = right_table.b .... Also, USING implies that only one of each pair of equivalent columns will be included in the join output, not both.
select *
from current_exclusive
full join current_table using (id_station, area_type)
full join current_cashier using (id_station, area_type)
You cannot accomplish anything if you insist on using select *, since you are getting the values from different tables.
The option you have is to include a COALESCE block which gives you the first non-null value from the list of columns.
So, you could use.
select COALESCE( current_exclusive.id_station, current_table.id_station, current_cashier.id_station ) as id_station ,
COALESCE( current_exclusive.area_type , current_table.area_type, current_cashier.area_type ) as area_type ,.....
...
from current_exclusive
full join current_table..
...
I would like to solve this issue avoiding to use cursors (FETCH).
Here comes the problem...
1st Table/quantity
------------------
periodid periodstart periodend quantity
1 2010/10/01 2010/10/15 5
2st Table/sold items
-----------------------
periodid periodstart periodend solditems
14343 2010/10/05 2010/10/06 2
Now I would like to get the following view or just query result
Table Table/stock
-----------------------
periodstart periodend itemsinstock
2010/10/01 2010/10/04 5
2010/10/05 2010/10/06 3
2010/10/07 2010/10/15 5
It seems impossible to solve this problem without using cursors, or without using single dates instead of periods.
I would appreciate any help.
Thanks
DECLARE #t1 TABLE (periodid INT,periodstart DATE,periodend DATE,quantity INT)
DECLARE #t2 TABLE (periodid INT,periodstart DATE,periodend DATE,solditems INT)
INSERT INTO #t1 VALUES(1,'2010-10-01T00:00:00.000','2010-10-15T00:00:00.000',5)
INSERT INTO #t2 VALUES(14343,'2010-10-05T00:00:00.000','2010-10-06T00:00:00.000',2)
DECLARE #D1 DATE
SELECT #D1 = MIN(P) FROM (SELECT MIN(periodstart) P FROM #t1
UNION ALL
SELECT MIN(periodstart) FROM #t2) D
DECLARE #D2 DATE
SELECT #D2 = MAX(P) FROM (SELECT MAX(periodend) P FROM #t1
UNION ALL
SELECT MAX(periodend) FROM #t2) D
;WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS i FROM L4),
Dates AS(SELECT DATEADD(DAY,i-1,#D1) AS D FROM Nums where i <= 1+DATEDIFF(DAY,#D1,#D2)) ,
Stock As (
SELECT D ,t1.quantity - ISNULL(t2.solditems,0) AS itemsinstock
FROM Dates
LEFT OUTER JOIN #t1 t1 ON t1.periodend >= D and t1.periodstart <= D
LEFT OUTER JOIN #t2 t2 ON t2.periodend >= D and t2.periodstart <= D ),
NStock As (
select D,itemsinstock, ROW_NUMBER() over (order by D) - ROW_NUMBER() over (partition by itemsinstock order by D) AS G
from Stock)
SELECT MIN(D) AS periodstart, MAX(D) AS periodend, itemsinstock
FROM NStock
GROUP BY G, itemsinstock
ORDER BY periodstart
Hopefully a little easier to read than Martin's. I used different tables and sample data, hopefully extrapolating the right info:
CREATE TABLE [dbo].[Quantity](
[PeriodStart] [date] NOT NULL,
[PeriodEnd] [date] NOT NULL,
[Quantity] [int] NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[SoldItems](
[PeriodStart] [date] NOT NULL,
[PeriodEnd] [date] NOT NULL,
[SoldItems] [int] NOT NULL
) ON [PRIMARY]
INSERT INTO Quantity (PeriodStart,PeriodEnd,Quantity)
SELECT '20100101','20100115',5
INSERT INTO SoldItems (PeriodStart,PeriodEnd,SoldItems)
SELECT '20100105','20100107',2 union all
SELECT '20100106','20100108',1
The actual query is now:
;WITH Dates as (
select PeriodStart as DateVal from SoldItems union select PeriodEnd from SoldItems union select PeriodStart from Quantity union select PeriodEnd from Quantity
), Periods as (
select d1.DateVal as StartDate, d2.DateVal as EndDate
from Dates d1 inner join Dates d2 on d1.DateVal < d2.DateVal left join Dates d3 on d1.DateVal < d3.DateVal and d3.DateVal < d2.DateVal where d3.DateVal is null
), QuantitiesSold as (
select StartDate,EndDate,COALESCE(SUM(si.SoldItems),0) as Quantity
from Periods p left join SoldItems si on p.StartDate < si.PeriodEnd and si.PeriodStart < p.EndDate
group by StartDate,EndDate
)
select StartDate,EndDate,q.Quantity - qs.Quantity
from QuantitiesSold qs inner join Quantity q on qs.StartDate < q.PeriodEnd and q.PeriodStart < qs.EndDate
And the result is:
StartDate EndDate (No column name)
2010-01-01 2010-01-05 5
2010-01-05 2010-01-06 3
2010-01-06 2010-01-07 2
2010-01-07 2010-01-08 4
2010-01-08 2010-01-15 5
Explanation: I'm using three Common Table Expressions. The first (Dates) is gathering all of the dates that we're talking about, from the two tables involved. The second (Periods) selects consecutive values from the Dates CTE. And the third (QuantitiesSold) then finds items in the SoldItems table that overlap these periods, and adds their totals together. All that remains in the outer select is to subtract these quantities from the total quantity stored in the Quantity Table
John, what you could do is a WHILE loop. Declare and initialise 2 variables before your loop, one being the start date and the other being end date. Your loop would then look like this:
WHILE(#StartEnd <= #EndDate)
BEGIN
--processing goes here
SET #StartEnd = #StartEnd + 1
END
You would need to store your period definitions in another table, so you could retrieve those and output rows when required to a temporary table.
Let me know if you need any more detailed examples, or if I've got the wrong end of the stick!
Damien,
I am trying to fully understand your solution and test it on a large scale of data, but I receive following errors for your code.
Msg 102, Level 15, State 1, Line 20
Incorrect syntax near 'Dates'.
Msg 102, Level 15, State 1, Line 22
Incorrect syntax near ','.
Msg 102, Level 15, State 1, Line 25
Incorrect syntax near ','.
Damien,
Based on your solution I also wanted to get a neat display for StockItems without overlapping dates. How about this solution?
CREATE TABLE [dbo].[SoldItems](
[PeriodStart] [datetime] NOT NULL,
[PeriodEnd] [datetime] NOT NULL,
[SoldItems] [int] NOT NULL
) ON [PRIMARY]
INSERT INTO SoldItems (PeriodStart,PeriodEnd,SoldItems)
SELECT '20100105','20100106',2 union all
SELECT '20100105','20100108',3 union all
SELECT '20100115','20100116',1 union all
SELECT '20100101','20100120',10
;WITH Dates as (
select PeriodStart as DateVal from SoldItems
union
select PeriodEnd from SoldItems
union
select PeriodStart from Quantity
union
select PeriodEnd from Quantity
), Periods as (
select d1.DateVal as StartDate, d2.DateVal as EndDate
from Dates d1
inner join Dates d2 on d1.DateVal < d2.DateVal
left join Dates d3 on d1.DateVal < d3.DateVal and
d3.DateVal < d2.DateVal where d3.DateVal is null
), QuantitiesSold as (
select StartDate,EndDate,SUM(si.SoldItems) as Quantity
from Periods p left join SoldItems si on p.StartDate < si.PeriodEnd and si.PeriodStart < p.EndDate
group by StartDate,EndDate
)
select StartDate,EndDate, qs.Quantity
from QuantitiesSold qs
where qs.quantity is not null