create table table1 (
header bit,
[type] char(1),
Intype varchar(3),
agrid int,
affid int,
inno varchar(10),
amount int
);
create table table2 (
header bit,
[type] char(1),
Intype varchar(3),
agrid int,
affid int,
inno varchar(10),
amount int
);
Scenario 1:
insert into table1 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(0, 'D','001',18,84,'001',null),
(0, 'N', '001', 18,84,'001',null);
insert into table2 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(1, null, null,18,84, '001', 90),
(1, null, null,18,84, '001', 60),
(1, null, null,18,84, '001', 84);
For every header trailer 0 record, i need to show the related trailer 1 record joining on inno , affid, agrid. Please let m eknow how can i achieve this
I need:
header , [type] , Intype ,agrid , affid, inno,amount
0 , 'D' , '001' , 18 , 84 , '001' , null ----table 1 record for type D
1 , null, null, 18, 84, 001, 90
1, null, null,18,84, 001, 60
1, null, null,18,84, 001, 84
0, 'N', '001', 18,84,'001',null ----table 1 record for type N
1 , null, null, 18, 84, 001, 90
1, null, null,18,84, 001, 60
1, null, null,18,84, 001, 84
0, 'N', '001', 18,84,'001',null
Scenario 2:
insert into table1 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(0, 'D','001',14,95,'001',null),
(0, 'D', '001', 14,95,'008',null),
(0, 'N', '001', 14,95,'008',null);
insert into table2 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(1, null, null,14,95, '001', 11),
(1, null, null,14,95, '008', 23);
I need:
header , [type] , Intype ,agrid , affid, inno,amount
0, 'D','001',14,95,'001',null ----table 1 record for type D
1, null, null,14,95, 001, 11
0, 'D', '001', 14,95,'008',null ---table 1 record for type D
1, null, null,14,95, 008, 23
0, 'N', '001', 14,95,'008',null ----table 1 record for type N
1, null, null,14,95, 008, 23
I tried with some joins, it didn't work.
You can try to sort then, by adding more columns
the main part is that both get a row_number that can join table1 and table1, the constant sorter is necessary as header is binary and can only handle two different tables, if you have more, it will be useful
To get the right order for amount, you need an aditional sorting column, like an indetidy
Tables are by nature unsorted, so the result can differ
SELECT
header , [type] , Intype ,agrid , affid, inno,amount,
ROW_NUMBER() OVER(PARTITION BY agrid , affid, inno ORDER BY agrid) rn,1 sorter
FROM table1
UNION ALL
SELECT
t2.header , t2.[type] , t2.Intype ,t2.agrid , t2.affid, t2.inno,t2.amount,
t1.rn,2
FROM table2 t2 JOIN (SELECT
header , [type] , Intype ,agrid , affid, inno,amount,
ROW_NUMBER() OVER(PARTITION BY agrid , affid, inno ORDER BY agrid) rn
FROM table1)
t1 ON t1.agrid = t2.agrid
AND t1.affid = t2.affid AND t1.inno = t2.inno
ORDER BY agrid , affid, inno,rn,sorter
header
type
Intype
agrid
affid
inno
amount
rn
sorter
False
D
001
18
84
001
null
1
1
True
null
null
18
84
001
90
1
2
True
null
null
18
84
001
60
1
2
True
null
null
18
84
001
84
1
2
False
N
001
18
84
001
null
2
1
True
null
null
18
84
001
90
2
2
True
null
null
18
84
001
84
2
2
True
null
null
18
84
001
60
2
2
truncate table table1
truncate table table2
insert into table1 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(0, 'D','001',14,95,'001',null),
(0, 'D', '001', 14,95,'008',null),
(0, 'N', '001', 14,95,'008',null);
insert into table2 (header , [type] , Intype ,agrid , affid, inno,amount)
values
(1, null, null,14,95, '001', 11),
(1, null, null,14,95, '008', 23);
5 rows affected
SELECT
header , [type] , Intype ,agrid , affid, inno,amount,
ROW_NUMBER() OVER(PARTITION BY agrid , affid, inno ORDER BY agrid) rn,1 sorter
FROM table1
UNION ALL
SELECT
t2.header , t2.[type] , t2.Intype ,t2.agrid , t2.affid, t2.inno,t2.amount,
t1.rn,2
FROM table2 t2 JOIN (SELECT
header , [type] , Intype ,agrid , affid, inno,amount,
ROW_NUMBER() OVER(PARTITION BY agrid , affid, inno ORDER BY agrid) rn
FROM table1)
t1 ON t1.agrid = t2.agrid
AND t1.affid = t2.affid AND t1.inno = t2.inno
ORDER BY agrid , affid, inno,rn,sorter
header
type
Intype
agrid
affid
inno
amount
rn
sorter
False
D
001
14
95
001
null
1
1
True
null
null
14
95
001
11
1
2
False
D
001
14
95
008
null
1
1
True
null
null
14
95
008
23
1
2
False
N
001
14
95
008
null
2
1
True
null
null
14
95
008
23
2
2
fiddle
Related
I have set of vehicle parts stored in two tables as per below:
Source Table1:
Vehicle_ID
Part1
Part2
Part3
Part4
Part5
1
10
20
30
2
10
20
3
10
Source Table2:
Vehicle_ID
Part6
Part7
Part8
Part9
Part10
1
40
2
30
50
60
3
30
Required Table like below:
Vehicle_ID
Part1
Part2
Part3
Part4
Part5
1
10
20
30
40
2
10
20
30
50
60
3
10
30
Maximum of the Part column up to 5 only.
I tried Union all statement but that statement is not relevant for excluding blank columns.
Please share your experience to solve my problem .
You need to unpivot and pivot the rows in both tables.
Data:
SELECT *
INTO Table1
FROM (VALUES
(1, 10, 20, 30, NULL, NULL),
(2, 10, 20, NULL, NULL, NULL),
(3, 10, NULL, NULL, NULL, NULL),
(4, 40, NULL, NULL, NULL, NULL)
) v (Vehicle_ID, Part1, Part2, Part3, Part4, Part5)
SELECT *
INTO Table2
FROM (VALUES
(1, 40, NULL, NULL, NULL, NULL),
(2, 30, 50, 60, NULL, NULL),
(3, 30, NULL, NULL, NULL, NULL),
(5, 50, NULL, NULL, NULL, NULL)
) v (Vehicle_ID, Part6, Part7, Part8, Part9, Part10)
Statement:
SELECT
Vehicle_ID,
MAX(CASE WHEN RN = 1 THEN Part END) AS Part1,
MAX(CASE WHEN RN = 2 THEN Part END) AS Part2,
MAX(CASE WHEN RN = 3 THEN Part END) AS Part3,
MAX(CASE WHEN RN = 4 THEN Part END) AS Part4,
MAX(CASE WHEN RN = 5 THEN Part END) AS Part5
FROM (
SELECT
COALESCE(t1.Vehicle_ID, t2.Vehicle_ID) AS Vehicle_ID,
a.*,
ROW_NUMBER() OVER (PARTITION BY COALESCE(t1.Vehicle_ID, t2.Vehicle_ID) ORDER BY a.Part_ID) AS RN
FROM Table1 t1
FULL OUTER JOIN Table2 t2 ON t1.Vehicle_ID = t2.Vehicle_ID
CROSS APPLY (VALUES
(1, t1.Part1),
(2, t1.Part2),
(3, t1.Part3),
(4, t1.Part4),
(5, t1.Part5),
(6, t2.Part6),
(7, t2.Part7),
(8, t2.Part8),
(9, t2.Part9),
(10, t2.Part10)
) a (Part_ID, Part)
WHERE a.Part IS NOT NULL
) t
GROUP BY Vehicle_ID
Result:
Vehicle_ID
Part1
Part2
Part3
Part4
Part5
1
10
20
30
40
2
10
20
30
50
60
3
10
30
4
40
5
50
I have a table as follows:
Type_id name Comments
-------------------
61 a aa
62 a Test2
62 b bb
63 c cc
63 b bb
63 c bb
64 c cc
Now I would like to select the result set as follows:
Type_id name Comments
-------------------
61 a aa
62 a Test2
b bb
63 c cc
b bb
c bb
64 c cc
The duplicate Type_id should display an empty string if there are multiple values. I tried using CASE statements but without much luck.
Here is the query that I have tried with:
select
case when Type_id = 61 then 'Cell1'
when Type_id = 62 then 'Cell2'
when Type_id = 63 then 'Cell3'
else ''
end as Type_id,
name,
Comments
FROM
TBL
where
CATEGORY_ID = 120
order by Type_id
Can anyone help me. Thanks in advance.
I used a combination of LAG and CASE to solve:
CREATE TABLE #temp (ID VARCHAR(2), [name] VARCHAR (1), comment VARCHAR(10))
INSERT INTO #temp (ID, [name], comment)
VALUES
(61 , 'a' , 'aa' ),
(62 , 'a' , 'Test2' ),
(62 , 'b' , 'bb' ),
(63 , 'c' , 'cc' ),
(63, 'b' , 'bb' ),
(63 , 'c' , 'bb' ),
(64 , 'c' , 'cc' );
SELECT CASE WHEN id = (LAG(id, 1, 0) OVER (ORDER BY Id))
THEN ''
ELSE id
END AS id,
[name],
comment
FROM #temp
DROP TABLE #temp
here is my version
--temp data
if object_id('tempdb..#x') is not null drop table #x
CREATE TABLE #x(type_id INT, name VARCHAR(1), comments VARCHAR(20))
INSERT INTO #x(type_id, name, comments) VALUES
( 61, 'a', 'aa'),
( 62, 'a', 'Test2'),
( 62, 'b', 'bb'),
( 63, 'c', 'cc'),
( 63, 'b', 'bb'),
(63, 'c', 'bb'),
(64, 'c', 'cc')
--query
SELECT CASE WHEN type_id=LAG(type_id,1,0) OVER(ORDER BY type_id) THEN NULL ELSE type_id END AS 'type_id',
name, comments
FROM #x
output
type_id name comments
61 a aa
62 a Test2
NULL b bb
63 c cc
NULL b bb
NULL c bb
64 c cc
If you don't have LAG as the requester states
if object_id('tempdb..#x') is not null drop table #x
CREATE TABLE #x(type_id INT, name VARCHAR(1), comments VARCHAR(20))
INSERT INTO #x(type_id, name, comments) VALUES
( 61, 'a', 'aa'),
( 62, 'a', 'Test2'),
( 62, 'b', 'bb'),
( 63, 'c', 'cc'),
( 63, 'b', 'bb'),
(63, 'c', 'bb'),
(64, 'c', 'cc')
if object_id('tempdb..#a') is not null drop table #a
SELECT x.*,
ROW_NUMBER() OVER(PARTITION BY x.type_id ORDER BY x.type_id) AS 'id_count'
INTO #a
FROM #x AS x
SELECT CASE WHEN a.id_count>1 THEN NULL ELSE a.type_id END AS 'type_id',
a.name, a.comments
FROM #a AS a
select
case when row_number() -- only return 1st value
over (partition by Type_id
order by name) = 1
then cast(Type_id as varchar(10))
else ''
end as Type_id,
name,
Comments
FROM
TBL
where
CATEGORY_ID = 120
order by Type_id, name -- same order by used in ROW_NUMBER
As the questions suggests, is there a way to do mathematical operations on the same column except different rows?
Example.
Table A:
X Y Time New_time
0 aaa bbb 5 3
1 aaa bbb 2 1
2 aaa bbb 1 null
i want to find the difference in time for each row. So row 0 would have new_time as 3min. How would I go about doing this?
Thank you in advance.
You can use LEAD analytic function introduced in SQL Server 2012:
CREATE TABLE [dbo].[Times]
(
[ID] [INT] IDENTITY(1, 1)
NOT NULL ,
[X] [NVARCHAR](50) NOT NULL ,
[Y] [NVARCHAR](50) NOT NULL ,
[Time] [INT] NOT NULL
);
INSERT INTO [dbo].[Times]
( X, Y, [Time] )
VALUES ( 'aaa', 'bbb', 5 ),
( 'aaa', 'bbb', 2 ),
( 'aaa', 'bbb', 1 );
SELECT * ,
New_Time = [Time] - ( LEAD([Time]) OVER ( ORDER BY ID ) )
FROM [Times];
And the output will be:
declare #Table1 table(id int, x varchar(10), y varchar(10), [time] int)
insert into #Table1 values
(0,'aaa', 'bbb', 5)
,(1,'aaa', 'bbb', 2)
,(2,'aaa', 'bbb', 1)
select *,
[time] - LEAD([Time]) over(order by id) as NewTime
from #Table1
I have two sets of interval data I.E.
Start End Type1 Type2
0 2 L NULL
2 5 L NULL
5 7 L NULL
7 10 L NULL
2 3 NULL S
3 5 NULL S
5 8 NULL S
11 12 NULL S
What I'd like to do is merge these sets into one. This seems possible by utilising an islands and gaps solution but due to the non-continuous nature of the intervals I'm not sure how to go about applying it... The output I'm expecting would be:
Start End Type1 Type2
0 2 L NULL
2 3 L S
3 5 L S
5 7 L S
7 8 L S
8 10 L NULL
11 12 NULL S
Anyone out there done something like this before??? Thanks!
Create script below:
CREATE TABLE Table1
([Start] int, [End] int, [Type1] varchar(4), [Type2] varchar(4))
;
INSERT INTO Table1
([Start], [End], [Type1], [Type2])
VALUES
(0, 2, 'L', NULL),
(2, 3, NULL, 'S'),
(2, 5, 'L', NULL),
(3, 5, NULL, 'S'),
(5, 7, 'L', NULL),
(5, 8, NULL, 'S'),
(7, 10, 'L', NULL),
(11, 12, NULL, 'S')
;
I assume that Start is inclusive, End is exclusive and given intervals do not overlap.
CTE_Number is a table of numbers. Here it is generated on the fly. I have it as a permanent table in my database.
CTE_T1 and CTE_T2 expand each interval into the corresponding number of rows using a table of numbers. For example, interval [2,5) generates rows with Values
2
3
4
This is done twice: for Type1 and Type2.
Results for Type1 and Type2 are FULL JOINed together on Value.
Finally, a gaps-and-islands pass groups/collapses intervals back.
Run the query step-by-step, CTE-by-CTE and examine intermediate results to understand how it works.
Sample data
I added few rows to illustrate a case when there is a gap between values.
DECLARE #Table1 TABLE
([Start] int, [End] int, [Type1] varchar(4), [Type2] varchar(4))
;
INSERT INTO #Table1 ([Start], [End], [Type1], [Type2]) VALUES
( 0, 2, 'L', NULL),
( 2, 3, NULL, 'S'),
( 2, 5, 'L', NULL),
( 3, 5, NULL, 'S'),
( 5, 7, 'L', NULL),
( 5, 8, NULL, 'S'),
( 7, 10, 'L', NULL),
(11, 12, NULL, 'S'),
(15, 20, 'L', NULL),
(15, 20, NULL, 'S');
Query
WITH
e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
) -- 10
,e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b) -- 10*10
,e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2) -- 10*100
,CTE_Numbers
AS
(
SELECT ROW_NUMBER() OVER (ORDER BY n) AS Number
FROM e3
)
,CTE_T1
AS
(
SELECT
T1.[Start] + CA.Number - 1 AS Value
,T1.Type1
FROM
#Table1 AS T1
CROSS APPLY
(
SELECT TOP(T1.[End] - T1.[Start]) CTE_Numbers.Number
FROM CTE_Numbers
ORDER BY CTE_Numbers.Number
) AS CA
WHERE
T1.Type1 IS NOT NULL
)
,CTE_T2
AS
(
SELECT
T2.[Start] + CA.Number - 1 AS Value
,T2.Type2
FROM
#Table1 AS T2
CROSS APPLY
(
SELECT TOP(T2.[End] - T2.[Start]) CTE_Numbers.Number
FROM CTE_Numbers
ORDER BY CTE_Numbers.Number
) AS CA
WHERE
T2.Type2 IS NOT NULL
)
,CTE_Values
AS
(
SELECT
ISNULL(CTE_T1.Value, CTE_T2.Value) AS Value
,CTE_T1.Type1
,CTE_T2.Type2
,ROW_NUMBER() OVER (ORDER BY ISNULL(CTE_T1.Value, CTE_T2.Value)) AS rn
FROM
CTE_T1
FULL JOIN CTE_T2 ON CTE_T2.Value = CTE_T1.Value
)
,CTE_Groups
AS
(
SELECT
Value
,Type1
,Type2
,rn
,ROW_NUMBER() OVER
(PARTITION BY rn - Value, Type1, Type2 ORDER BY Value) AS rn2
FROM CTE_Values
)
SELECT
MIN(Value) AS [Start]
,MAX(Value) + 1 AS [End]
,Type1
,Type2
FROM CTE_Groups
GROUP BY rn-rn2, Type1, Type2
ORDER BY [Start];
Result
+-------+-----+-------+-------+
| Start | End | Type1 | Type2 |
+-------+-----+-------+-------+
| 0 | 2 | L | NULL |
| 2 | 8 | L | S |
| 8 | 10 | L | NULL |
| 11 | 12 | NULL | S |
| 15 | 20 | L | S |
+-------+-----+-------+-------+
A step-by-step way is:
-- Finding all break points
;WITH breaks AS (
SELECT Start
FROM yourTable
UNION
SELECT [End]
FROM yourTable
) -- Finding Possible Ends
, ends AS (
SELECT Start
, (SELECT Min([End]) FROM yourTable WHERE yourTable.Start = breaks.Start) End1
, (SELECT Max([End]) FROM yourTable WHERE yourTable.Start < breaks.Start) End2
FROM breaks
) -- Finding periods
, periods AS (
SELECT Start,
CASE
WHEN End1 > End2 And End2 > Start THEN End2
WHEN End1 IS NULL THEN End2
ELSE End1
END [End]
FROM Ends
WHERE NOT(End1 IS NULL AND Start = End2)
) -- Generating results
SELECT p.Start, p.[End], Max(Type1) Type1, Max(Type2) Type2
FROM periods p, yourTable t
WHERE p.start >= t.Start AND p.[End] <= t.[End]
GROUP BY p.Start, p.[End];
In above query some situations may not fit at analyzing all of them, you can improve it as you want ;).
First getting all the numbers of start and end via a Union.
Then joining those numbers on both the 'L' and 'S' records.
Uses a table variable for the test.
DECLARE #Table1 TABLE (Start int, [End] int, Type1 varchar(4), Type2 varchar(4));
INSERT INTO #Table1 (Start, [End], Type1, Type2)
VALUES (0, 2, 'L', NULL),(2, 3, NULL, 'S'),(2, 5, 'L', NULL),(3, 5, NULL, 'S'),
(5, 7, 'L', NULL),(5, 8, NULL, 'S'),(7, 10, 'L', NULL),(11, 12, NULL, 'S');
select
n.Num as Start,
(case when s.[End] is null or l.[End] <= s.[End] then l.[End] else s.[End] end) as [End],
l.Type1,
s.Type2
from
(select Start as Num from #Table1 union select [End] from #Table1) n
left join #Table1 l on (n.Num >= l.Start and n.Num < l.[End] and l.Type1 = 'L')
left join #Table1 s on (n.Num >= s.Start and n.Num < s.[End] and s.Type2 = 'S')
where (l.Start is not null or s.Start is not null)
order by Start, [End];
Output:
Start End Type1 Type2
0 2 L NULL
2 3 L S
3 5 L S
5 7 L S
7 8 L S
8 10 L NULL
11 12 NULL S
I have a table With data like below (Table 1)
id valueId Value
----------- ----------- --------------------------------------------------
1 1 Value 1
1 1 Value 2
1 1 Value 3
1 2 Value 1
1 2 Value 2
1 2 Value 3
And i have another dataset like below (DataSet)
id valueId Value
----------- ----------- -------
1 1 Value 1
1 1 Value 2
1 1 Value 4
now i need to insert records that are not exists in the Table 1 (You can see the record
id valueId Value
----------- ----------- -------
1 1 Value 4
is not in the Table 1, that record should insert) and need to delete records from Table 1 that are not in DataSet which is
id valueId Value
----------- ----------- -------
1 1 Value 3
, but without affecting other records (other records means records that id=1 and valueId=2).
I have used the following T-SQL that i have wrote it using MERGE, It inserts the missing records but it deletes all the records that are not in the DataSet
DECLARE #tmp_value AS TABLE
(
id INT ,
valueId INT ,
[Value] NVARCHAR(50)
) ;
INSERT #tmp_value
( [id], [valueId], [Value] )
VALUES ( 1, 1, N'Value 1' ),
( 1, 1, N'Value 2' ),
( 1, 1, N'Value 3' ),
( 1, 2, N'Value 1' ),
( 1, 2, N'Value 2' ),
( 1, 2, N'Value 3' ) ;
--SELECT *
--FROM #tmp_value AS TV ;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON [cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value]
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
WHEN NOT MATCHED BY SOURCE
THEN DELETE ;
SELECT *
FROM #tmp_value
Expected Result:
id valueId Value
----------- ----------- --------------------------------------------------
1 1 Value 1
1 1 Value 2
1 1 Value 4
1 2 Value 1
1 2 Value 2
1 2 Value 3
Update :
DECLARE #tmp_value AS TABLE
(
id INT ,
valueId INT ,
[Value] NVARCHAR(50)
) ;
INSERT #tmp_value
( [id], [valueId], [Value] )
VALUES ( 1, 1, N'Value 1' ),
( 1, 1, N'Value 2' ),
( 1, 1, N'Value 3' ),
( 1, 2, N'Value 1' ),
( 1, 2, N'Value 2' ),
( 1, 2, N'Value 3' ) ;
--SELECT *
--FROM #tmp_value AS TV ;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON [cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value]
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
;
WITH cte
AS ( SELECT 1 AS id , 1 AS valueId , 'Value 1' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 2' AS [Value]
UNION
SELECT 1 AS id , 1 AS valueId , 'Value 4' AS [Value]
)
MERGE #tmp_value AS TV
USING cte
ON ([cte].[id] = [TV].[id]
AND [cte].[valueId] = [TV].[valueId]
AND [cte].[Value] = [TV].[Value])
or not( [TV].[id] in (select distinct id from cte)
and [TV].[valueId] in (select distinct valueid from cte))
WHEN NOT MATCHED
THEN INSERT VALUES ( id , [valueId] , [Value] )
WHEN NOT MATCHED BY Source
THEN DELETE ;
SELECT *
FROM #tmp_value