I need use CTE with two tables - sql

I have 2 tables and I need to use a CTE.
I need a set of rows of Table_2 on rows from Table_1, such that dActiveDate is biggest in table_1, and table_1.dActiveDate <= table_2.dDateFactor for table_1.dcidKala = table_2.dcidKala.
CREATE TABLE #Table_1
(
dcidKala INT,
dcPercentDiscount FLOAT,
dActiveDate DATE
)
CREATE TABLE #Table_2
(
dcRow INT,
dcidKala INT,
dcNum FLOAT,
dDateFactor DATE
)
INSERT INTO #Table_1
(
dcidKala,
dcPercentDiscount,
dActiveDate
)
VALUES
(109,10,'2017-08-23' ),
(109, 15, '2017-10-12'),
(100, 20, '2017-01-20'),
(102, 20, '2017-01-20')
INSERT INTO #Table_2
(
dcRow,
dcidKala,
dcNum,
dDateFactor
)
VALUES
( 1,109,1, '2017-10-05' ),
(2, 109, 2, '2017-10-07'),
(3, 109, 1, '2017-10-14'),
(4, 109, 5, '2017-10-19'),
(5, 100, 2, '2017-01-25')
;WITH cte AS
(
SELECT th.dcPercentDiscount,
tb.dcRow,
ROW_NUMBER() OVER(PARTITION BY th.dcidKala, tb.dcRow ORDER BY th.dActiveDate) AS
rn
FROM #Table_1 th
INNER JOIN #Table_2 tb
ON tb.dcidKala = th.dcidKala
AND tb.dDateFactor >= th.dActiveDate
)
SELECT *
FROM #Table_2 t2
LEFT JOIN cte t3
ON t2.dcRow = t3.dcRow
AND t3.rn = 1
DROP TABLE [#Table_1]
DROP TABLE [#Table_2]
--result myCode is:
--1 109 1 2017-10-05 10 1 1
--2 109 2 2017-10-07 10 2 1
--3 109 1 2017-10-14 10 3 1
--4 109 5 2017-10-19 10 4 1
--5 100 2 2017-01-25 20 5 1
--Rows 3 and Rows 4 is wrong
--i need this result :
-- on Result From table_1 on table_2
--1 109 1 2017-10-05 10 1 1
--2 109 2 2017-10-07 10 2 1
--3 109 1 2017-10-14 15 3 1
--4 109 5 2017-10-19 15 4 1
--5 100 2 2017-01-25 20 5 1
For each row in table_2 just one result from table_1 that is biggest on
dActiveDate and smaller dDateFactor
Please help me
thank you

You can use this.
;WITH cte AS
(
SELECT
th.dcPercentDiscount, tb.dcRow,
ROW_NUMBER() OVER(PARTITION BY th.dcidKala, tb.dcRow ORDER BY th.dActiveDate DESC) AS rn
FROM
Table_1 th
INNER JOIN
Table_2 tb ON tb.dcidKala = th.dcidKala
AND tb.dDateFactor >= th.dActiveDate
)
SELECT *
FROM Table_2 t2
LEFT JOIN cte t3 ON t2.dcRow = t3.dcRow and t3.rn=1

CREATE TABLE #Table_1 (dcidKala INT,
dcPercentDiscount FLOAT,
dActiveDate DATE)
CREATE TABLE #Table_2 (dcRow INT,
dcidKala INT,
dcNum FLOAT,
dDateFactor DATE)
INSERT INTO #Table_1 (dcidKala,
dcPercentDiscount,
dActiveDate)
VALUES (100, 10, '2017-01-01'),
(101, 15, '2017-01-02'),
(100, 20, '2017-01-20'),
(102, 20, '2017-01-20')
INSERT INTO #Table_2 (dcRow,
dcidKala,
dcNum,
dDateFactor)
VALUES (1, 100, 1, '2017-01-05'),
(2, 100, 2, '2017-01-09'),
(3, 101, 1, '2017-01-01'),
(4, 101, 5, '2017-01-20'),
(5, 100, 2, '2017-01-25')
SELECT *
FROM [#Table_2] AS [t2]
CROSS APPLY ( SELECT TOP 1 *
FROM ( SELECT TOP 1 [t1].[dcidKala],
[t1].[dcPercentDiscount],
[t1].[dActiveDate]
FROM [#Table_1] AS [t1]
WHERE [t1].[dcidKala] = [t2].[dcidKala]
AND [t2].[dDateFactor] >= [t1].[dActiveDate]
ORDER BY [t1].[dActiveDate] DESC
UNION ALL
SELECT NULL,
NULL,
NULL) t3
ORDER BY CASE
WHEN [t2].[dcidKala] IS NOT NULL THEN 0
ELSE 1
END) AS t1
DROP TABLE [#Table_1]
DROP TABLE [#Table_2]

Related

How can distribute one table data to another table

I have two tables Orderapproval and stock:
Table 1: Orderapproval
itemcode
approvalqty
1
25
2
10
Table 2: stock
itemcode
stockqty
batch
date
1
5
aa
2021-02-01
1
10
bb
2021-02-10
1
15
cc
2021-02-02
2
5
dd
2021-02-01
2
20
aa
2021-02-05
we have stock batch-wise.
when we get an order request for an item
we are trying to pick up items from the old batch first & so on
How can I get a result set like this:
itemcode
qty
batch
date
1
5
aa
2021-02-01
1
15
cc
2021-02-02
1
5
bb
2021-02-10
2
5
dd
2021-02-01
I am trying as......
Declare #StockTable table
(ItemCode int,BranchCode int,Qty int)
Insert Into #StockTable values
(1, 101, 5),
(1, 102, 10),
(1, 101, 15),
(2, 102, 5),
(2, 103, 20)
Declare #Orderapproval table (ItemCode int,Qty int)
Insert Into #Orderapproval values
(1,25),
(2,10)
;with T1 as (
Select A.*
,ToDist = cast(D.Qty as int),
running_total = SUM(D.Qty) OVER (PARTITION BY A.ItemCode,BranchCode ORDER BY BranchCode DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
From #StockTable A
Join #Orderapproval D on A.ItemCode=D.ItemCode )
, T2 as (
Select *, prev_running_total = LAG(Qty,1,0) OVER (PARTITION BY ItemCode ORDER BY BranchCode DESC) From T1
)
select *,
CASE WHEN prev_running_total >= ToDist THEN 0
WHEN running_total > ToDist THEN ToDist - prev_running_total
ELSE qty
END 'qty'
from T2;
I didn't get the right output.
Please suggest a better way
Try this:
SELECT s.itemcode
, s.stockqty AS qty
, s.batch
, s.date
FROM stock AS s
INNER JOIN Orderapproval AS oa
ON s.stockqty <= oa.approvalqty
If required, insert resultset into new table
I try it on SQLite 3.30
Schema
CREATE TABLE stock (
id INT,
itemcode INT,
stockqty INT,
batch CHAR,
date DATE
);
INSERT INTO stock (id, itemcode, stockqty, batch, date) VALUES (1, 1, 5, 'aa', '2021-02-01');
INSERT INTO stock (id, itemcode, stockqty, batch, date) VALUES (2, 1, 10, 'bb', '2021-02-10');
INSERT INTO stock (id, itemcode, stockqty, batch, date) VALUES (3, 1, 15, 'cc', '2021-02-02');
INSERT INTO stock (id, itemcode, stockqty, batch, date) VALUES (4, 2, 5, 'dd', '2021-02-01');
INSERT INTO stock (id, itemcode, stockqty, batch, date) VALUES (5, 2, 20, 'aa', '2021-02-05');
CREATE TABLE orderapproval (
id INT,
itemcode INT,
approvalqty INT
);
INSERT INTO orderapproval (id, itemcode, approvalqty) VALUES (1, 1, 25);
INSERT INTO orderapproval (id, itemcode, approvalqty) VALUES (2, 2, 10);
Query
with a as ( SELECT *, sum(stockqty) over (partition by itemcode order by date ) as acc FROM stock)
select a.itemcode, case when acc<=approvalqty then stockqty else approvalqty-(acc-stockqty) end as qty, batch, date from a
inner join orderapproval o
on a.itemcode = o.itemcode
where qty > 0
order by a.itemcode, date
Result
itemcode
qty
batch
date
1
5
aa
2021-02-01
1
15
cc
2021-02-02
1
5
bb
2021-02-10
2
5
dd
2021-02-01
2
5
aa
2021-02-05
db-fiddle
SQL CODE---(Tested)
Select stock.itemcode
,stock.stockqty AS qty
,stock.batch,stock.date
from stock
join orderapproval on stock.stockqty <= orderapproval.approvalgty
group by stock.batch;

change data format from rows to columns

I have a SQL table in the below format. Every ID has 2 entries in the table for a particular date.
Input:
ID date rownum subid value1 value2
A 200911 1 X 10 20
A 200911 2 Y 15 25
B 201001 2 S 60 35
B 201001 1 R 40 50
I want to write a SQL query to change this to the below format, so that every ID/date combination has only 1 entry as shown below. The rownum is already included and the values should be represented so that rownnum 1 is displayed first and then the value with rownum second as shown below.
Output:
ID date row1subid row1value1 row1value2 row2subid row2value1 row2value2
A 200911 X 10 20 Y 15 25
B 201001 R 40 50 S 60 35
Let me know if something is not clear.
Thanks for all your help!
Here is what you need to do as a SQL Fiddle.
And for reference:
CREATE TABLE TestData
([ID] varchar(1),
[date] int,
[rownum] int,
[subid] varchar(1),
[value1] int,
[value2] int)
;
INSERT INTO TestData
([ID], [date], [rownum], [subid], [value1], [value2])
VALUES
('A', 200911, 1, 'X', 10, 20),
('A', 200911, 2, 'Y', 15, 25),
('B', 201001, 2, 'S', 60, 35),
('B', 201001, 1, 'R', 40, 50)
;
SELECT A.ID, A.date, A.rownum, A.subid, A.value1, A.value2, B.value1 AS r2value1, B.value2 AS r2value2
FROM TestData AS A
INNER JOIN TestData B ON A.id = B.id AND B.rownum = 2
WHERE A.rownum = 1

Full Outer Join on Incomplete Data (by id variable)

I have two tables (see example data below). I need to keep all of the ID values in table 1 and merge table 1 with table 2 by sequence. The tricky part is that I also have to retain the field value1 from table 1 and value2 from table 2.
table 1 :
ID sequence value1
-------------------------
p1 1 5
p1 2 10
p2 1 15
p2 2 20
table 2 :
sequence value2
-------------------------
1 10
2 20
3 30
4 40
I need the resulting table to appear like so:
ID sequence value1 value2
----------------------------------
p1 1 5 10
p1 2 10 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40
I have tried the following sql code, but it doesn't merge the missing values from from value1 field in table 1 and merge it with the values2 field from table 2
select t1.ID, t2.sequence, t1.value1, t2.value2 from
t2 full outer join t1 on t2.sequence=t1.sequence
Any assistance you can provide is greatly appreciated.
You can try something like this:
select coalesce(t1.[id], t3.[id]),
, t2.[sequence]
, t1.[value]
, t2.[value]
from [tbl2] t2
left join [tbl1] t1 on t1.[sequence] = t2.[sequence]
left join (select distinct [id] from [tbl1]) t3 on t1.[id] is null
SQLFiddle
One way with CROSS JOIN and OUTER APPLY:
DECLARE #t1 TABLE(ID CHAR(2), S INT, V1 INT)
DECLARE #t2 TABLE(S INT, V2 INT)
INSERT INTO #t1 VALUES
('p1', 1, 5),
('p1', 2, 10),
('p2', 1, 15),
('p2', 2, 20)
INSERT INTO #t2 VALUES
(1, 10),
(2, 20),
(3, 30),
(4, 40)
SELECT c.ID, t2.S, ca.V1, t2.V2 FROM #t2 t2
CROSS JOIN (SELECT DISTINCT ID FROM #t1) c
OUTER APPLY(SELECT * FROM #t1 t1 WHERE c.ID = t1.ID AND t1.S = t2.S) ca
ORDER BY c.ID, t2.S
Output:
ID S V1 V2
p1 1 5 10
p1 2 10 20
p1 3 NULL 30
p1 4 NULL 40
p2 1 15 10
p2 2 20 20
p2 3 NULL 30
p2 4 NULL 40
Given this schema:
create table #table_1
(
ID varchar(8) not null ,
sequence int not null ,
value int not null ,
primary key clustered ( ID , sequence ) ,
unique nonclustered ( sequence , ID ) ,
)
create table #table_2
(
sequence int not null ,
value int not null ,
primary key clustered ( sequence ) ,
)
go
insert #table_1 values ( 'p1' , 1 , 5 )
insert #table_1 values ( 'p1' , 2 , 5 )
insert #table_1 values ( 'p2' , 1 , 15 )
insert #table_1 values ( 'p2' , 2 , 20 )
insert #table_2 values ( 1 , 10 )
insert #table_2 values ( 2 , 20 )
insert #table_2 values ( 3 , 30 )
insert #table_2 values ( 4 , 40 )
go
This should get you what you want:
select ID = map.ID ,
sequence = map.sequence ,
value1 = t1.value ,
value2 = t2.value
from ( select distinct
t1.ID ,
t2.sequence
from #table_1 t1
cross join #table_2 t2
) map
left join #table_1 t1 on t1.ID = map.ID
and t1.sequence = map.sequence
join #table_2 t2 on t2.sequence = map.sequence
order by map.ID ,
map.sequence
go
Producing:
ID sequence value1 value2
== ======== ====== ======
p1 1 5 10
p1 2 5 20
p1 3 - 30
p1 4 - 40
p2 1 15 10
p2 2 20 20
p2 3 - 30
p2 4 - 40

How to merge ranges from different tables

Giving the following 2 tables:
T1
------------------
From | To | Value
------------------
10 | 20 | XXX
20 | 30 | YYY
30 | 40 | ZZZ
T2
------------------
From | To | Value
------------------
10 | 15 | AAA
15 | 19 | BBB
19 | 39 | CCC
39 | 40 | DDD
What is the best way to get the result below, using T-SQL on SQL Server 2008?
The From/To ranges are sequential (there are no gaps) and the next From always has the same value as the previous To
Desired result
-------------------------------
From | To | Value1 | Value2
-------------------------------
10 | 15 | XXX | AAA
15 | 19 | XXX | BBB
19 | 20 | XXX | CCC
20 | 30 | YYY | CCC
30 | 39 | ZZZ | CCC
39 | 40 | ZZZ | DDD
First I declare data that looks like the data you posted. Please correct me if any assumptions I have made are wrong. Better would be to post your own declaration in the question so we are all working with the same data.
DECLARE #T1 TABLE (
[From] INT,
[To] INT,
[Value] CHAR(3)
);
INSERT INTO #T1 (
[From],
[To],
[Value]
)
VALUES
(10, 20, 'XXX'),
(20, 30, 'YYY'),
(30, 40, 'ZZZ');
DECLARE #T2 TABLE (
[From] INT,
[To] INT,
[Value] CHAR(3)
);
INSERT INTO #T2 (
[From],
[To],
[Value]
)
VALUES
(10, 15, 'AAA'),
(15, 19, 'BBB'),
(19, 39, 'CCC'),
(39, 40, 'DDD');
Here is my select query to generate your expected result:
SELECT
CASE
WHEN [#T1].[From] > [#T2].[From]
THEN [#T1].[From]
ELSE [#T2].[From]
END AS [From],
CASE
WHEN [#T1].[To] < [#T2].[To]
THEN [#T1].[To]
ELSE [#T2].[To]
END AS [To],
[#T1].[Value],
[#T2].[Value]
FROM #T1
INNER JOIN #T2 ON
(
[#T1].[From] <= [#T2].[From] AND
[#T1].[To] > [#T2].[From]
) OR
(
[#T2].[From] <= [#T1].[From] AND
[#T2].[To] > [#T1].[From]
);
Stealing #isme's data setup, I wrote the following:
;With EPs as (
select [From] as EP from #T1
union
select [To] from #T1
union
select [From] from #T2
union
select [To] from #T2
), OrderedEndpoints as (
select EP,ROW_NUMBER() OVER (ORDER BY EP) as rn from EPs
)
select
oe1.EP,
oe2.EP,
t1.Value,
t2.Value
from
OrderedEndpoints oe1
inner join
OrderedEndpoints oe2
on
oe1.rn = oe2.rn - 1
inner join
#T1 t1
on
oe1.EP < t1.[To] and
oe2.EP > t1.[From]
inner join
#T2 t2
on
oe1.EP < t2.[To] and
oe2.EP > t2.[From]
That is, you create a set containing all of the possible end points of periods (EPs), then you "sort" those and assign each one a row number (OrderedEPs).
Then the final query assembles each "adjacent" pair of rows together, and joins back to the original tables to find which rows from each one overlap the selected range.
The below query finds the smallest ranges, then picks the values back out the tables again:
SELECT ranges.from, ranges.to, T1.Value, T2.Value
FROM (SELECT all_from.from, min(all_to.to) as to
FROM (SELECT T1.FROM
FROM T1
UNION
SELECT T2.FROM
FROM T2) all_from
JOIN (SELECT T1.TO
FROM T1
UNION
SELECT T2.FROM
FROM T2) all_to ON all_from.from < all_to.to
GROUP BY all_from.from) ranges
JOIN T1 ON ranges.from >= T1.from AND ranges.to <= T1.to
JOIN T2 ON ranges.from >= T2.from AND ranges.to <= T2.to
ORDER BY ranges.from
Thanks for the answers, but I ended using a CTE, wgich I think is cleaner.
DECLARE #T1 TABLE ([From] INT, [To] INT, [Value] CHAR(3));
DECLARE #T2 TABLE ([From] INT, [To] INT, [Value] CHAR(3));
INSERT INTO #T1 ( [From], [To], [Value]) VALUES (10, 20, 'XXX'), (20, 30, 'YYY'), (30, 40, 'ZZZ');
INSERT INTO #T2 ( [From], [To], [Value]) VALUES (10, 15, 'AAA'), (15, 19, 'BBB'), (19, 39, 'CCC'), (39, 40, 'DDD');
;with merged1 as
(
select
t1.[From] as from1,
t1.[to] as to1,
t1.Value as Value1,
t2.[From] as from2,
t2.[to] as to2,
t2.Value as Value2
from #t1 t1
inner join #T2 t2
on t1.[From] < t2.[To]
and t1.[To] >= t2.[From]
)
,merged2 as
(
select
case when from2>=from1 then from2 else from1 end as [From]
,case when to2<=to1 then to2 else to1 end as [To]
,value1
,value2
from merged1
)
select * from merged2

Consolidating subsets in a table

I have a table in SqlServer 2008 with data of the form
UserID StartWeek EndWeek Type
1 1 3 A
1 4 5 A
1 6 10 A
1 11 13 B
1 14 16 A
2 1 5 A
2 6 9 A
2 10 16 B
I'd like to consolidate/condense the adjacent types so that the resulting table looks like this.
UserID StartWeek EndWeek Type
1 1 10 A
1 11 13 B
1 14 16 A
2 1 9 A
2 10 16 B
Does anyone have any suggestions as to the best way to accomplish this? I've been looking at using Row_number and Partition, but I can't get it to behave exactly as I'd like.
There's probably a neater way to do it, but this produces the correct result
DECLARE #t TABLE
(UserId TINYINT
,StartWeek TINYINT
,EndWeek TINYINT
,TYPE CHAR(1)
)
INSERT #t
SELECT 1,1,3,'A'
UNION SELECT 1,4,5,'A'
UNION SELECT 1,6,10,'A'
UNION SELECT 1,11,13,'B'
UNION SELECT 1,14,16,'A'
UNION SELECT 2,1,5,'A'
UNION SELECT 2,6,9,'A'
UNION SELECT 2,10,16,'B'
;WITH srcCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY t1.UserID, t1.Type
ORDER BY t1.EndWeek
) AS rn
FROM #t AS t1
)
,recCTE
AS
(
SELECT *
,0 AS grp
FROM srcCTE
WHERE rn = 1
UNION ALL
SELECT s.UserId
,s.StartWeek
,s.EndWeek
,s.TYPE
,s.rn
,CASE WHEN s.StartWeek - 1 = r.EndWeek
THEN r.grp
ELSE r.grp+ 1
END AS GRP
FROM srcCTE AS s
JOIN recCTE AS r
ON r.UserId = s.UserId
AND r.TYPE = s.TYPE
AND r.rn = s.rn - 1
)
SELECT UserId
,MIN(StartWeek) AS StartWeek
,MAX(EndWeek) AS EndWeek
,TYPE
FROM recCTE AS s1
GROUP BY UserId
,TYPE
,grp
Also using a CTE, but in a slightly different way
DECLARE #Consolidate TABLE (
UserID INTEGER, StartWeek INTEGER,
EndWeek INTEGER, Type CHAR(1))
INSERT INTO #Consolidate VALUES (1, 1, 3, 'A')
INSERT INTO #Consolidate VALUES (1, 4, 5, 'A')
INSERT INTO #Consolidate VALUES (1, 6, 10, 'A')
INSERT INTO #Consolidate VALUES (1, 14, 16, 'A')
INSERT INTO #Consolidate VALUES (1, 11, 13, 'B')
INSERT INTO #Consolidate VALUES (2, 1, 5, 'A')
INSERT INTO #Consolidate VALUES (2, 6, 9, 'A')
INSERT INTO #Consolidate VALUES (2, 10, 16, 'B')
;WITH ConsolidateCTE AS
(
SELECT UserID, StartWeek, EndWeek, Type
FROM #Consolidate
UNION ALL
SELECT cte.UserID, cte.StartWeek, c.EndWeek, c.Type
FROM ConsolidateCTE cte
INNER JOIN #Consolidate c ON
c.UserID = cte.UserID
AND c.StartWeek = cte.EndWeek + 1
AND c.Type = cte.Type
)
SELECT UserID, [StartWeek] = MIN(Startweek), EndWeek, Type
FROM (
SELECT UserID, Startweek, [EndWeek] = MAX(EndWeek), Type
FROM ConsolidateCTE
GROUP BY UserID, StartWeek, Type
) c
GROUP BY UserID, EndWeek, Type
ORDER BY 1, 2, 3