How to Pivot this resultset in SQL Server - 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

Related

NULLS being removed in unpivot

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)
)
.....

Based on territory, get the top customers and their total sales in percentage

Using adventureworks database.
I am stuck with top 5 customers based on the territory. How can we get the output for this in the given format?
SELECT TOP 5 CustomerID
,oh.TerritoryID
,Name
,SUM(TotalDue) / (
SELECT SUM(TotalDue)
FROM Sales.SalesOrderHeader
) * 100 AS [%_of_TotalSale]
FROM Sales.SalesOrderHeader oh
INNER JOIN Sales.SalesTerritory st ON st.TerritoryID = oh.TerritoryID
GROUP BY oh.TerritoryID
,CustomerID
,Name
ORDER BY [%_of_TotalSale] DESC;
My output
The output should look like this
Your query have some issues. You need to calculated the total per territory - not the whole total.
Note, the code below can be separated to individual statements. Also, there are other solutions of this task.
WITH DataSource AS
(
SELECT DISTINCT TerritoryID
,CustomerID
,SUM(TotalDue) OVER (PARTITION BY TerritoryID,CustomerID) * 100 / SUM(TotalDue) OVER (PARTITION BY TerritoryID) AS [%_of_TotalSale]
FROM Sales.SalesOrderHeader
), DataSourceUsersRanked AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY TerritoryID ORDER BY [%_of_TotalSale] DESC) AS RN
FROM DataSource
), DataSourceUsersFiletred AS
(
SELECT *
FROM DataSourceUsersRanked
WHERE RN <= 5
)
SELECT DSF.TerritoryID
,st.[Name]
,SUM([%_of_TotalSale]) AS [%_of_TotalSale]
,MAX(UserIDs) AS [Top5Customers]
FROM DataSourceUsersFiletred DSF
INNER JOIN Sales.SalesTerritory st
ON DSF.TerritoryID = st.TerritoryID
CROSS APPLY
(
SELECT STUFF
(
(
SELECT ',' + CAST(CustomerID AS VARCHAR(12))
FROM DataSourceUsersFiletred DS1
WHERE DS1.[TerritoryID] = DSF.[TerritoryID]
ORDER BY CustomerID
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)')
,1
,1
,''
)
) Users(UserIDs)
GROUP BY DSF.TerritoryID
,st.[Name]
ORDER BY TerritoryID;

How do I select the top 1 results of the if the same identifier exist? SQL Server

I have a data table in sql server 2008 that I would like to select the top 1 out of each identifier:
The results shld looks like this during before and after:
Thus it should only select the 1st results if the same identifier do exist. Thanks a lot.
select distinct [Primary Identifier] from tbl
If you have entire records (other columns) instead of that single column, you can row number them and choose one.
select {list of columns}
from
(
select *, rn = row_number over (partition by [Primary Identifier]
order by 1/0)
from tbl
) X
where rn = 1;
order by 1/0 is arbitrary. If you need to choose a specific one from the "duplicates", for example the highest cost, you order by cost descending, i.e.
(partition by [Primary Identifier]
order by [cost] descending)
Just distinct them:
select distinct [primary identifier] from tablename
Or by grouping:
select [primary identifier] from tablename group by [primary identifier]
If more columns exist you can rank rows with window function:
;with cte as(select *, row_number() over(partition by [primary identifier] order by (select null)) rn from tablename)
select * from cte where rn = 1
Change order by (select null) to appropriate ordering column.
i think this will be an appropriate solution to your need-
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY [Primary Identifier] ORDER BY [sort columns]) AS rowid
FROM [table]
)
SELECT *
FROM cte
WHERE rowid = 1

Converting Rows to Columns

I have a table with columns UserID and CountryName
Now I want get record in this way
[UserId] [ContryName1] [ContryName2] [ContryName3].........
Fiddle here : http://sqlfiddle.com/#!6/cd6f1/1
DECLARE #SQL AS NVARCHAR(MAX)
WITH CTE AS
(
SELECT USERID,COUNTRYNAME,ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY COUNTRYNAME) AS RN
FROM CNTRIES
)
SELECT #SQL = 'WITH CTE1 AS
(
SELECT USERID,COUNTRYNAME,ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY COUNTRYNAME) AS RN
FROM CNTRIES
)
SELECT *
FROM
(SELECT USERID,COUNTRYNAME,RN FROM CTE1)C
PIVOT (MAX(COUNTRYNAME) FOR RN IN (['+STUFF((SELECT '],['+CAST(RN AS VARCHAR(100))
FROM CTE
GROUP BY RN
FOR XML PATH('')),1,3,'')+'])) AS PIVOTT'
PIVOT is your best option if your version is SQL Server 2005 or above, but you don't state the version and trying to use PIVOT without a natural aggregate can be difficult to grasp for some. If your version is below 2005, you have bigger problems. Otherwise, you'll need to left join the table on itself to give you the same result. You can use a ranking function to make it a little easier. Something like this, while inefficient, will produce similar results.
/*
IF OBJECT_ID('Countries','U') IS NOT NULL
DROP TABLE Countries
CREATE TABLE Countries
(
UserID INT
, CountryName VARCHAR(255)
)
INSERT Countries
VALUES (1, 'India')
, (1, 'UK')
, (2, 'USA')
, (2, 'India')
, (2, 'Canada')
*/
SELECT DISTINCT x.UserID, x.CountryName Country1, y.CountryName Country2, z.CountryName Country3
FROM Countries c
LEFT JOIN
(
SELECT *, RANK() OVER(PARTITION BY UserID ORDER BY UserID, CountryName) AS UserRank
FROM Countries
)x ON x.UserID = c.UserID AND x.UserRank=1
LEFT JOIN
(
SELECT *, RANK() OVER(PARTITION BY UserID ORDER BY UserID, CountryName) AS UserRank
FROM Countries
)y ON y.UserID = c.UserID AND y.UserRank=2
LEFT JOIN
(
SELECT *, RANK() OVER(PARTITION BY UserID ORDER BY UserID, CountryName) AS UserRank
FROM Countries
)z ON z.UserID = c.UserID AND z.UserRank=3

How to optimize the query, adding rowNumber in where clause

In a table I have more than 700,000 records. When I run this query it takes more than 3 minutes to fetch the rows, and returns 390 records based on rowNum. Is there way to optimize this query?
SELECT ID, Lat, Long, SDateTime,
row_number() OVER (partition BY [ID] ORDER BY [SDateTime] DESC) AS rowNum
into #temp
FROM
dbo.myTable WITH (NOLOCK)
select * from #temp where rowNum = 1 -- returns 390 records
drop table #temp
Can I select data in one query without putting it in temp table? like this:
SELECT ID, Lat, Long, SDateTime,
row_number() OVER (partition BY [ID] ORDER BY [SDateTime] DESC) AS rowNum
FROM
dbo.myTable WITH (NOLOCK)
where (row_number() OVER (partition BY [ID] ORDER BY [SDateTime] DESC)) = 1
try doing this !
select * from
(
SELECT ID, Lat, Long, SDateTime,
row_number() OVER (partition BY [ID] ORDER BY [SDateTime] DESC) AS rowNum
FROM
dbo.myTable WITH (NOLOCK)
)x
where x.rowNum=1
This should do the job, but it will work very well with an index on (id,SDateTime)
;with d as (
select distinct id
from myTable
)
select
mt.*
from d
cross apply (
select top 1 *
from myTable m
on m.id = d.id
order by [SDateTime] DESC
) mt

Resources