NULLS being removed in unpivot - sql-server

I currently have the following code
with physician_diag as (
SELECT baseentityid, eventdate,locationid,teamid,average_muac,child_age,child_gender,physician_diagnosis, dignosis_data
FROM [VITAL_DWH].[vr].[event_physician_visit]
UNPIVOT
(dignosis_data FOR physician_diagnosis IN
(
well_baby,
severe_pneumonia
)
)
AS unpvt
),
final as (
-- Final
select *, dense_rank() OVER (PARTITION BY baseentityid ORDER BY eventdate) AS rn from (
select * from physician_diag
) F
The problem is that NULLS are being removed, so I am missing out on some of the original rows. Any idea how to fix this? I have read that cross join lateral is a possible way, but I could not get a grip on how to implement that. Please help.

UNPIVOT removes nulls. You can instead use CROSS APPLY (VALUES to unpivot, this is in any case much more flexible.
with physician_diag as (
SELECT
baseentityid,
eventdate,
locationid,
teamid,
average_muac,
child_age,
child_gender,
physician_diagnosis,
dignosis_data
FROM vr.event_physician_visit epv
CROSS APPLY (VALUES
('well_baby', epv.well_baby),
('severe_pneumonia', epv.severe_pneumonia)
) v(physician_diagnosis, dignosis_data)
),
final as (
select *,
dense_rank() OVER (PARTITION BY baseentityid ORDER BY eventdate) AS rn
from physician_diag
)
.....
I note that you could possibly put the DENSE_RANK before unpivoting, which may allow it to hit an index. The results should be the same in this case.
with ranked as (
select *,
dense_rank() OVER (PARTITION BY epv.baseentityid ORDER BY epv.eventdate) AS rn
from vr.event_physician_visit epv
),
final as (
SELECT
baseentityid,
eventdate,
locationid,
teamid,
average_muac,
child_age,
child_gender,
physician_diagnosis,
dignosis_data
FROM ranked epv
CROSS APPLY (VALUES
('well_baby', epv.well_baby),
('severe_pneumonia', epv.severe_pneumonia)
) v(physician_diagnosis, dignosis_data)
)
.....

Related

How to Pivot this resultset in SQL Server

Could you please help me to pivot the dataset ?
SELECT
[ParentFormId], [FieldName], value, [RowValidTo],
RANK() OVER (ORDER BY [RowValidTo] DESC) AS Sno
FROM
[asite].[viewK80FormField]
CROSS APPLY
STRING_SPLIT ([FieldValue], ',') AS t
WHERE
ParentFormId = '30571360'
AND FieldName IN ('docid', 'docrev', 'docPublishDate')
SQL Server, result set to be pivoted
Attempted PIVOT query:
WITH CTE_DocAttri AS
(
SELECT *
FROM
(SELECT
[ParentFormId], [FieldName], value, [RowValidTo],
RANK() OVER (PARTITION BY [FieldName] ORDER BY [RowValidTo] DESC) AS Sno
FROM
[asite].[viewK80FormField]
CROSS APPLY
STRING_SPLIT ([FieldValue], ',') AS t
WHERE
ParentFormId = '30571360'
AND FieldName IN ('docid', 'docrev', 'docPublishDate')
) AS source_table
PIVOT
(MAX([Value])
FOR [FieldName] IN (docPublishDate, DocID, DocRev)
) AS PivotTABLE
)
SELECT
ParentFormId, docPublishDate, DocID, DocRev
FROM
CTE_DocAttri
Result for the pivot query (Getting only one row)
ParentFormId
docPublishDate
DocID
DocRev
30571360
28/04/2021
53079864
2
enter image description hereGot the resultset atlast,
WITH cte_docattri
AS (SELECT *
FROM (SELECT [parentformid],
[fieldname],
value,
[rowvalidto],
Row_number()
OVER (
partition BY [parentformid], fieldname
ORDER BY [rowvalidto] DESC) AS Sno
FROM [asite].[viewk80formfield]
CROSS apply String_split ([fieldvalue], ',') AS t
WHERE parentformid = '30571360'
AND fieldname IN ( 'docid', 'docrev', 'docPublishDate' )
)AS
source_table
PIVOT ( Max([value])
FOR [fieldname] IN (docpublishdate,
docid,
docrev) ) AS pivottable)
SELECT sno,
parentformid,
docpublishdate,
docid,
docrev
FROM cte_docattri

How to get desired result by combining two CTE's with different tables?

I have two CTE's,firstly
;WITH CTE AS (SELECT A.*
, Row_NUMBER() Over (Partition by ID order by Date asc) RN
FROM TABLE A)
SELECT Sum(Weight) as IN_WT
FROM CTE
WHERE RN = 1 and name='dev1'
and then
;WITH CTE AS (SELECT B.*
, Row_NUMBER() Over (Partition by ID order by Date desc) RN1
FROM TABLE B)
SELECT Sum(Weight) AS out_wt
FROM CTE
WHERE RN1 = 1 and name='dev1'
Here we had two tablesTableA,TableB.We are getting In_wt from TableA and Out_wt from TableB.Now I had a requiremnt that the output should be combined and get in_wt,out_wt in single row from different tables and same name.I tried combining both the CTE's but didn't get the desired result.How can we do that?
Try this:
;WITH CTE1 AS (
SELECT name,
Row_NUMBER() Over (Partition by ID order by Date asc) RN
FROM TABLEA
), CTE2 AS (
SELECT name,
Row_NUMBER() Over (Partition by ID order by Date desc) RN
FROM TABLEB
)
SELECT (SELECT Sum(Weight) FROM CTE1 WHERE RN = 1 and name='dev1') AS IN_WT,
(SELECT Sum(Weight) FROM CTE2 WHERE RN = 1 and name='dev1') AS OUT_WT

Filtering FREETEXTTABLE output by rank for optimization

I'm trying to optimize the following query which returns products matching search phrase:
WITH [RankedQuery] AS
(
SELECT FTS.RANK, ROW_NUMBER() OVER (ORDER BY [FTS].RANK DESC) AS [RowNumber], [Product].*
FROM [Product]
INNER JOIN FREETEXTTABLE([Product],
(
[Name],
[Brand],
[Category],
[Description]
), 'man shoes') AS [FTS]
ON FTS.[Key] = [Product].[Id]
)
SELECT * FROM [RankedQuery]
WHERE [RowNumber] BETWEEN 100 AND 150
I found in the execution plan that it spends most time sorting the results by RANK - which makes sense, as it has to go through many rows that are not really necessary.
I tried to optimize it by filtering the products by rank before sorting, but the results were poor.
The query:
WITH [RankedQuery] AS
(
SELECT MaxRelevance, FTS.RANK, ROW_NUMBER() OVER (ORDER BY [FTS].RANK DESC) AS [RowNumber], [Product].*
FROM [Product]
INNER JOIN
(
select * from
(
select FTS_stage_1.*, max(FTS_stage_1.rank) over() as MaxRelevance
from FREETEXTTABLE
([Product],
(
[Name],
[Brand],
[Category],
[Description]
), 'man shoes'
)
as FTS_stage_1
) AS [FTS_with_MaxRelevance]
where [FTS_with_MaxRelevance].Rank > [FTS_with_MaxRelevance].MaxRelevance * 0.3
) AS [FTS]
ON FTS.[Key] = [Product].[Id]
)
SELECT * FROM [RankedQuery]
WHERE [RowNumber] BETWEEN 100 AND 150
resulted in this monstrosity, and a couple times longer execution time.
Is there a way to make it more efficient?

SQL Server 2000: How to get top 10 for each distinct field. A loop Maybe?

I have the following table
MyTable
ID
MessageType
MessageDate
MessageBody
The table is a few million rows but there are only 100 unique MessageType in it.
What I need is a sample of each MessageType (must include at least MessageType and MessageBody), but I can't do a DISTINCT as that only gets me the MessageType column.
I am thinking something like
SELECT TOP 5 *
FROM MyTable
WHERE MessageType IN (SELECT DISTINCT MessageType FROM MyTable)
I know this doesn't work as it just me the top 5, but I am not sure how to make SQL loop through this.
Thanks for any help
The Row_Number version
;WITH cte AS
(
SELECT ID,
MessageType,
MessageDate,
MessageBody,
ROW_NUMBER() OVER (PARTITION BY MessageType ORDER BY (SELECT 0)) AS RN
FROM MyTable
)
SELECT ID,
MessageType,
MessageDate,
MessageBody
FROM cte
WHERE RN <=5
The CROSS APPLY version
WITH m1 AS
(
SELECT DISTINCT MessageType
FROM MyTable
)
SELECT m2.*
FROM m1
CROSS APPLY
(
SELECT TOP 5 *
FROM MyTable m2
WHERE m2.MessageType = m1.MessageType
) m2
Martin, if I'm reading your answer correctly, I think what you will produce is 5 samples of each message. Marc_s just wants one sample from each message.
I think what you need is:
SELECT ID,
MessageType,
MessageDate
FROM (
SELECT ID,
MessageType,
MessageDate,
ROW_NUMBER() OVER (PARTITION BY MessageType, ORDER BY NEWID() ) AS RN
-- I am using NewID() because it will produce a nice random sampling,
-- but Mark's SELECT(0) will be faster.
FROM MyTable
) sampling
WHERE RN =1

SQL Server: join on derived table that contains WITH clause?

I'd like to join on a subquery / derived table that contains a WITH clause (the WITH clause is necessary to filter on ROW_NUMBER() = 1). In Teradata something similar would work fine, but Teradata uses QUALIFY ROW_NUMBER() = 1 instead of a WITH clause.
Here is my attempt at this join:
-- want to join row with max StartDate on JobModelID
INNER JOIN (
WITH AllRuns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY JobModelID ORDER BY StartDate DESC) AS RowNumber
FROM Runs
)
SELECT * FROM AllRuns WHERE RowNumber = 1
) Runs
ON JobModels.JobModelID = Runs.JobModelID
What am I doing wrong?
You could use multiple WITH clauses. Something like
;WITH AllRuns AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY JobModelID ORDER BY StartDate DESC) AS RowNumber
FROM Runs
),
Runs AS(
SELECT *
FROM AllRuns
WHERE RowNumber = 1
)
SELECT *
FROM ... INNER JOIN (
Runs ON JobModels.JobModelID = Runs.JobModelID
For more detail on the usages/structure/rules see WITH common_table_expression (Transact-SQL)
Adding a join condition is probably less efficient, but usually works fine for me.
INNER JOIN (
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY JobModelID
ORDER BY StartDate DESC) AS RowNumber
FROM Runs
) Runs
ON JobModels.JobModelID = Runs.JobModelID
AND Runs.RowNumber = 1

Resources