bound two query in single query both data will be show - sql-server

Query 1:
select * from(select* from (select Product_ID, batchno, Baleno,
SampleTime, Line, ItemData, ItemType from ItemData) d
pivot(sum(ItemData) for ItemType in (DYL, COLOR, STD)) as piv1) ff
where batchno = '001' AND Product_ID = '1' And Line = 'B'
Query 2:
select * from(select* from (select Product_ID, batchno, Baleno, SampleTime,
Line, ItemData, ItemType from ItemData) d
pivot(sum(ItemData) for ItemType in (DYL, COLOR, STD)) as piv1) ff
where batchno = '001' AND Product_ID = '1' And Line = 'A'

Use UNION ALL As below-
SELECT *
FROM
(
SELECT *
FROM
(
SELECT Product_ID,
batchno,
Baleno,
SampleTime,
Line,
ItemData,
ItemType
FROM ItemData
) d PIVOT(SUM(ItemData) FOR ItemType IN(DYL, COLOR, STD)) AS piv1
) ff
WHERE batchno = '001' AND Product_ID = '1' AND Line = 'B';
UNION ALL
SELECT *
FROM
(
SELECT *
FROM
(
SELECT Product_ID,
batchno,
Baleno,
SampleTime,
Line,
ItemData,
ItemType
FROM ItemData
) d PIVOT(SUM(ItemData) FOR ItemType IN(DYL, COLOR, STD)) AS piv1
) ff
WHERE batchno = '001' AND Product_ID = '1' AND Line = 'A';

Related

merge statement using a cte throwing an error

I'm attempting to convert a MSSQL Query into Snowflake and I'm getting tripped up when I'm attempting to update my table using a secondary CTE after applying some business logic.
CREATE TEMPORARY TABLE test
(
id integer,
src text,
val text
);
INSERT INTO test
SELECT t.*
FROM (
VALUES (1, 'A', 'AA')
, (1, 'A', 'AB') t(id, src, val)
)
SELECT * FROM TEST
+--+---+---+
|ID|SRC|VAL|
+--+---+---+
|1 |A |AA |
|1 |A |AB |
+--+---+---+
WITH dat AS (
SELECT id, src, val
, ROW_NUMBER() OVER(ORDER BY id) rn
FROM test
)
, src AS (
SELECT id, src, val,
MD5(
ARRAY_TO_STRING(
ARRAY_CONSTRUCT(id,src,val), ':'
)
) AS CHANGE_HASH
FROM dat
WHERE rn = 1
)
MERGE INTO target as tgt using src -- <-- this throws an error
ON src.id = tgt.id
AND src.CHANGE_HASH != tgt.CHANGE_HASH
THEN UPDATE
SET (
...
)
the error I get is
[42000][1003] SQL compilation error: syntax error line 61 at position 15 unexpected '<EOF>'.
Where is my mistake?
The CTE should be in the subquery like this:
MERGE INTO target as tgt using
(
WITH dat AS (
SELECT id, src, val
, ROW_NUMBER() OVER(ORDER BY id) rn
FROM test)
, src AS (
SELECT id, src, val,
MD5(
ARRAY_TO_STRING(
ARRAY_CONSTRUCT(id,src,val), ':'
)
) AS CHANGE_HASH
FROM dat
WHERE rn = 1 )
select * from src) src
ON src.id = tgt.id
AND src.CHANGE_HASH != tgt.CHANGE_HASH
WHEN MATCHED THEN UPDATE SET tgt.src = src.src;
The CTE is no needed as the entire section could be simplified with single QUALIFY:
SELECT id, src, val,
MD5(
ARRAY_TO_STRING(
ARRAY_CONSTRUCT(id,src,val), ':'
)
) AS CHANGE_HASH
FROM dat
QUALIFY ROW_NUMBER() OVER(ORDER BY id) = 1
is the same as:
WITH dat AS (
SELECT id, src, val
, ROW_NUMBER() OVER(ORDER BY id) rn
FROM test
)
, src AS (
SELECT id, src, val,
MD5(
ARRAY_TO_STRING(
ARRAY_CONSTRUCT(id,src,val), ':'
)
) AS CHANGE_HASH
FROM dat
WHERE rn = 1
)
and MERGE becomes:
MERGE INTO target as tgt
USING (
SELECT id, src, val,
MD5(
ARRAY_TO_STRING(
ARRAY_CONSTRUCT(id,src,val), ':'
)
) AS CHANGE_HASH
FROM dat
QUALIFY ROW_NUMBER() OVER(ORDER BY id) = 1
) AS src
ON ...
...;

Getting Numeric value not recognized

SELECT ID,INDEX,purchase_list,
NVL(CASE WHEN INDEX = 2 THEN purchase_list END,0)
AS qty,
sum(NVL(CASE WHEN INDEX = 2 THEN purchase_list END,0))over(partition by ID) as order_qty
FROM (
SELECT ID,index,d.value::string AS purchase_list FROM (
SELECT ID,c.value::string AS purchase_list
FROM table_1,LATERAL flatten(INPUT=>split(post_purchase_list, '|')) c
), LATERAL flatten(INPUT=>split(purchase_list, ';')) d
)WHERE ID=1250707
When I run the above query, I'm getting
Numeric value is not recognized.
The column - post_purchase_list is a VARCHAR column.
SELECT 'this is a string' as this_is_a_str,
NVL(this_is_a_str, 0) as one_of_these_is_str_and_the_other_is_a_number;
also gives:
Numeric value 'this is a string' is not recognized
Which to say, your types are different, ether cast your "string to a number if it is one" or cast your zero to a string '0'
SELECT '1234' as this_is_a_str,
0 as this_is_a_number,
NVL(this_is_a_str, this_is_a_number::string),
NVL(this_is_a_str::int, this_is_a_number);
this works just fine. Now for you code you are doing this twice.
SELECT
ID,
INDEX,
purchase_list,
NVL(CASE WHEN INDEX = 2 THEN purchase_list END, '0') AS qty,
sum(NVL(CASE WHEN INDEX = 2 THEN purchase_list END, '0')) over (partition by ID) as order_qty
FROM (
SELECT
ID,
index,
d.value::string AS purchase_list
FROM (
SELECT
ID,
c.value::string AS purchase_list
FROM table_1,
LATERAL flatten(INPUT=>split(post_purchase_list, '|')) c
), LATERAL flatten(INPUT=>split(purchase_list, ';')) d
)
WHERE ID = 1250707
but as mentioned before those flattens could be written
SELECT
ID,
INDEX,
purchase_list,
NVL(CASE WHEN INDEX = 2 THEN purchase_list END,'0') AS qty,
sum(NVL(CASE WHEN INDEX = 2 THEN purchase_list END,'0')) over (partition by ID) as order_qty
FROM (
SELECT
ID,
d.index,
d.value::string AS purchase_list
FROM table_1
,LATERAL flatten(INPUT=>split(post_purchase_list, '|')) c
,LATERAL flatten(INPUT=>split(c.value::string, ';')) d
)
WHERE ID = 1250707
and the qty can be reused:
SELECT
ID,
INDEX,
purchase_list,
NVL(CASE WHEN INDEX = 2 THEN purchase_list END,'0') AS qty,
sum(qty) over (partition by ID) as order_qty
FROM (
SELECT
ID,
d.index,
d.value::string AS purchase_list
FROM table_1
,LATERAL flatten(INPUT=>split(post_purchase_list, '|')) c
,LATERAL flatten(INPUT=>split(c.value::string, ';')) d
)
WHERE ID = 1250707
OR
SELECT
ID,
d.index,
d.value::string AS purchase_list,
NVL(CASE WHEN d.index = 2 THEN purchase_list END, '0') AS qty,
sum(qty) over (partition by ID) as order_qty
FROM table_1
,LATERAL flatten(INPUT=>split(post_purchase_list, '|')) c
,LATERAL flatten(INPUT=>split(c.value::string, ';')) d
WHERE ID = 1250707

Need help in using LISTAGG

WITH CTE AS (
SELECT
id,
c_no,
TRY_CAST(B.p_no as INTEGER) as p_no
FROM db_name.schema_name.tbl_1 A
JOIN db_name.schema_name.tbl_2 B
ON B.id_col = A.id_col
WHERE flg_col = '0'
AND cd NOT IN ('1','2','3','4')
AND DATE = '2022-02-02'
AND id='12345678'
ORDER BY p_no
)
SELECT
id,
LISTAGG (distinct c_no , ',') WITHIN GROUP (ORDER BY c_no) AS c01
FROM CTE
GROUP BY id;
When I run the above query, I'm getting result AS
Row ID C01
1 01 110,118,id_not_found,no_record
2 02 id_found
3 03 no_record
I want to display only the numberic values in C01 column in the result along with the corresponding ID. I want to ignore
these 2 values - id_not_found & no_record in the first row.
But in 2nd and 3rd, the value should remain same.
Any suggestions please.
Try to use the TRY_TO_NUMBER function:
WITH CTE AS (
SELECT
id,
c_no,
TRY_CAST(B.p_no as INTEGER) as p_no
FROM db_name.schema_name.tbl_1 A
JOIN db_name.schema_name.tbl_2 B
ON B.id_col = A.id_col
WHERE flg_col = '0'
AND cd NOT IN ('1','2','3','4')
AND DATE = '2022-02-02'
AND id='12345678'
ORDER BY p_no
)
SELECT
id,
IFNULL(LISTAGG(distinct TRY_TO_NUMBER(c_no) , ',') WITHIN GROUP(ORDER BY TRY_TO_NUMBER(c_no)), c_no) AS c01
FROM CTE
GROUP BY id;
The way you have describe it, is if "there are any number of include numbers, other all data is valid"
Using the smallest SQL that demonstrates the code and we do a little preconditioning in a CTE (which could be moved into your CTE)
WITH cte(id, c_no) AS (
SELECT * FROM VALUES
(01, '110'),
(01, '118'),
(01, 'id_not_found'),
(01, 'no_record'),
(02, 'id_found'),
(03, 'no_record')
), pre_condition AS (
SELECT *,
try_to_number(c_no) as c_no_as_num
FROM cte
)
SELECT
id,
count(c_no_as_num) as count_of_nums,
LISTAGG (distinct c_no , ',') WITHIN GROUP (ORDER BY c_no) AS c01_all,
LISTAGG (distinct c_no_as_num , ',') WITHIN GROUP (ORDER BY c_no_as_num) AS c01_nums,
IFF(count_of_nums>0, c01_nums, c01_all) AS c01
FROM pre_condition
GROUP BY id
ORDER BY id;
we get, the answer you want in C01:
ID
COUNT_OF_NUMS
C01_ALL
C01_NUMS
C01
1
2
110,118,id_not_found,no_record
110,118
110,118
2
0
id_found
id_found
3
0
no_record
no_record
so we can mash this smaller:
SELECT * FROM VALUES
(01, '110'),
(01, '118'),
(01, 'id_not_found'),
(01, 'no_record'),
(02, 'id_found'),
(03, 'no_record')
), pre_condition AS (
SELECT *,
try_to_number(c_no) as c_no_as_num
FROM cte
)
SELECT
id,
IFF(count(c_no_as_num)>0, LISTAGG (distinct c_no_as_num , ',') WITHIN GROUP (ORDER BY c_no_as_num), LISTAGG (distinct c_no , ',') WITHIN GROUP (ORDER BY c_no)) AS c01
FROM pre_condition
GROUP BY id
ORDER BY id;
and weave that into your code as:
WITH CTE AS (
SELECT
id,
c_no,
try_to_number(c_no) as c_no_as_num
TRY_CAST(B.p_no as INTEGER) as p_no
FROM db_name.schema_name.tbl_1 A
JOIN db_name.schema_name.tbl_2 B
ON B.id_col = A.id_col
WHERE flg_col = '0'
AND DATE = '2022-02-02'
AND id = '12345678'
AND cd NOT IN ('1','2','3','4')
)
SELECT
id,
IFF(count(c_no_as_num)>0
,LISTAGG (distinct c_no_as_num , ',') WITHIN GROUP (ORDER BY c_no_as_num)
,LISTAGG (distinct c_no , ',') WITHIN GROUP (ORDER BY c_no)
) AS c01
FROM cte
GROUP BY id
;

Trying to pivot event dates in t-sql without using a cursor

I have the following table:
What I want is to get to this:
EventTypeId 1 and 3 are valid start events and EventTypeId of 2 is the only valid end event.
I have tried to do a pivot, but I don't believe a pivot will get me the multiple events for a person in the result set.
SELECT PersonId, [1],[3],[2]
FROM
(
SELECT PersonId, EventTypeId, EventDate
from #PersonEvent
) as SourceTable
PIVOT
(
count(EventDate) FOR EventTypeId
IN ([1],[3],[2])
) as PivotTable
Select PersonID,
Min(Case WHEN EventTypeId IN (1,3) THEN EventDate END) as StartDate,
Min(Case WHEN EventTypeId IN (2) THEN EventDate END) as EndDate
FROM #PersonEvent
group by personid
I can do a cursor, but my original table is over 90,000 rows, and this is to be for a report, so I don't think I can use that option. Any other thoughts that I might be missing?
Assuming the table is called [dbo].[PersonEventRecords] this will work...
With StartEvents As
(
Select *
From [dbo].[PersonEventRecords]
Where EventTypeId In (1,3)
), EndEvents As
(
Select *
From [dbo].[PersonEventRecords]
Where EventTypeId In (2)
)
Select IsNull(se.PersonId,ee.PersonId) As PersonId,
se.EventTypeId As StartEventTypeId,
se.EventDate As StartEventDate,
ee.EventTypeId As EndEventTypeId,
ee.EventDate As EndEventDate
From StartEvents se
Full Outer Join EndEvents ee
On se.PersonId = ee.PersonId
And se.EventSequence = ee.EventSequence - 1
Order By IsNull(se.PersonId,ee.PersonId),
IsNull(se.EventDate,ee.EventDate);
/**** TEST DATA ****/
If Object_ID('[dbo].[PersonEventRecords]') Is Not Null
Drop Table [dbo].[PersonEventRecords];
Create Table [dbo].[PersonEventRecords]
(
PersonId Int,
EventTypeId Int,
EventDate Date,
EventSequence Int
);
Insert [dbo].[PersonEventRecords]
Select 1,1,'2012-10-13',1
Union All
Select 1,2,'2012-10-20',2
Union All
Select 1,1,'2012-11-01',3
Union All
Select 1,2,'2012-11-13',4
Union All
Select 2,1,'2012-05-07',1
Union All
Select 2,2,'2012-06-01',2
Union All
Select 2,3,'2012-07-01',3
Union All
Select 2,2,'2012-08-30',4
Union All
Select 3,2,'2012-04-05',1
Union All
Select 3,1,'2012-05-04',2
Union All
Select 3,2,'2012-05-24',3
Union All
Select 4,1,'2013-01-03',1
Union All
Select 4,1,'2013-02-20',2
Union All
Select 4,2,'2013-03-20',3;
Try this
SELECT E1.PersonId, E1.EventTypeId, E1.EventDate, E2.EventTypeId, E2.EventDate
FROM PersonEvent AS E1
OUTER APPLY(
SELECT TOP 1 PersonEvent.EventTypeId, PersonEvent.EventDate
FROM PersonEvent
WHERE PersonEvent.PersonId = E1.PersonId
AND PersonEvent.EventSequence = E1.EventSequence + 1
AND PersonEvent.EventTypeId = 2
) AS E2
WHERE E1.EventTypeId = 1 OR E1.EventTypeId = 3
UNION
SELECT E3.PersonId, NULL, NULL, E3.EventTypeId, E3.EventDate
FROM PersonEvent E3
WHERE E3.EventTypeId = 2
AND NOT EXISTS(
SELECT *
FROM PersonEvent
WHERE PersonEvent.PersonId = E3.PersonId
AND PersonEvent.EventSequence = E3.EventSequence - 1)
It is not completely clear how do you want the result to be ordered – add order as needed.

PIVOT on Common Table Expression

I have a CTE as follows
WITH details
AS ( SELECT FldId
,Rev
,Words
,row_number() OVER ( PARTITION BY FldId ORDER BY Rev DESC ) AS rn
FROM WorkItemLongTexts
WHERE ID = 2855
)
SELECT f.ReferenceName
,d.FldId
,Rev
,Words
FROM details AS d
INNER JOIN Fields AS f ON f.FldId = d.FldId
WHERE d.rn = 1 ;
The above returns the following output
ReferenceName | FldId | Rev | Words
Description 52 2 Description here
Objectives 10257 2 Objectives here
Specification 10258 6 Specification here
Requirements 10259 6 Requirements here
I want to apply PIVOT (or whatever is the best option) so that i can get output as follows
Description | Objectives | Specification | Requirements
Description here Objectives here Specification here Requirements here
Pls. suggest.
Thanks
You do this:
SELECT
FldId,
[Description],
[Objectives],
[Specification],
[Requirements]
FROM (
SELECT
ReferenceName,
FldId,
REV,
Words
FROM CTE
WHERE RowNumber = 1
) t
PIVOT (
MIN(Words)
FOR ReferenceName IN ([Description], [Objectives], [Specification], [Requirements])
) PIV
Or you can add it to your CTE, like this:
;WITH CTE2 AS (
SELECT
FldId,
REV,
[Description],
[Objectives],
[Specification],
[Requirements],
ROW_NUMBER() OVER (PARTITION BY FldId ORDER BY REV DESC) AS RowNumber
FROM TBL
PIVOT (
MIN(Words)
FOR ReferenceName IN ([Description], [Objectives], [Specification], [Requirements])
) PIV
)
SELECT
FldId,
REV,
[Description],
[Objectives],
[Specification],
[Requirements]
FROM CTE2
WHERE RowNumber = 1
WITH details
AS ( SELECT FldId
,Rev
,Words
,row_number() OVER ( PARTITION BY FldId ORDER BY Rev DESC ) AS rn
FROM WorkItemLongTexts
WHERE ID = 2855
),
cte_1
AS ( SELECT f.ReferenceName
,d.FldId
,Rev
,Words
FROM details AS d
INNER JOIN Fields AS f ON f.FldId = d.FldId
WHERE d.rn = 1
)
SELECT max(case [ReferenceName] WHEN 'Descripton' THEN [Words] ELSE NULL END) AS [Descripton]
,max(case [ReferenceName] WHEN 'Objectives' THEN [Words] ELSE NULL END) AS [Objectives]
,max(case [ReferenceName] WHEN 'Specification' THEN [Words] ELSE NULL END) AS [Specification]
,max(case [ReferenceName] WHEN 'Requirements' THEN [Words] ELSE NULL END) AS [Requirements]
FROM cte_1 ;
OR:
-- cte here as above
SELECT Description
,Objectives
,Specification
,Requirements
FROM cte_1 PIVOT ( max(Words) FOR ReferenceName IN ( Description,
Objectives,
Specification,
Requirements ) ) AS PivotTable
Do something like:
with details as (...)
, unpivotted as (select f.ReferenceName, Words
from details as d
inner join Fields as f
on f.FldId=d.FldId
where d.rn =1)
Select *
from unpivotted
pivot
(max(Words) for Description in ([Objectives],[Specification],[Requirements]) p
;

Resources