UNPIVIOT AND RANK the data - sql

I have a table with 24 hrs data, i want to pivot the data and assign a rank for them based on the counts.
create table #HourlyData_Counts
(Hr_1 int,Hr_2 int ,Hr_3 int,Hr_4 int,Hr_5 int ,Hr_6 int ,Hr_7 int , Hr_8 int ,Hr_9 int , Hr_10 int )
insert into #HourlyData_Counts
values (55,89,78,77,67,99,45,33,23,91)
select * from #HourlyData_Counts
--drop table #HourlyData_Counts
required output

You will need to use Unpivot in this case.
select Hours,counts,Ranks=Row_Number()over(order by counts)
from
(
select * from #HourlyData_Counts
) src
UNPIVOT
(
counts For Hours in(Hr_1,Hr_2,Hr_3,Hr_4,Hr_5,Hr_6,Hr_7,Hr_8,Hr_9,Hr_10)
) unpiv;

You are looking for unpivot, like this:
select
[Hours],
[counts],
rank() over (order by [counts] desc)
from
(
select * from #HourlyData_Counts
) as src
unpivot
(
[counts] for [Hours] in (Hr_1, Hr_2, Hr_3, Hr_4, Hr_5, Hr_6, Hr_7, Hr_8, Hr_9, Hr_10)
) as upvt
order by try_cast(replace([Hours], 'Hr_', '') as int)

CREATE TABLE #HourlyData_Counts
(Hr_1 int,Hr_2 int ,Hr_3 int,Hr_4 int,Hr_5 int ,Hr_6 int ,Hr_7 int , Hr_8 int ,Hr_9 int , Hr_10 int )
INSERT INTO #HourlyData_Counts
VALUES (55,89,78,77,67,99,45,33,23,91)
SELECT
[Hours]
, Counts
, RANK() OVER (ORDER BY Counts DESC) Ranks
FROM
(
SELECT Hr_1, Hr_2, Hr_3, Hr_4, Hr_5, Hr_6, Hr_7, Hr_8, Hr_9, Hr_10
FROM #HourlyData_Counts
) P
UNPIVOT
(
Counts FOR [Hours] IN
(Hr_1, Hr_2, Hr_3, Hr_4, Hr_5, Hr_6, Hr_7, Hr_8, Hr_9, Hr_10)
) U
ORDER BY CAST(REPLACE([Hours], 'Hr_', '') AS int)
DROP TABLE #HourlyData_Counts

IF OBJECT_ID('tempdb..#HourlyData_Counts') IS NOT NULL
DROP TABLE #HourlyData_Counts
create table #HourlyData_Counts
(Hr_1 int,Hr_2 int ,Hr_3 int,Hr_4 int,Hr_5 int ,Hr_6 int ,Hr_7 int , Hr_8 int ,Hr_9 int , Hr_10 int )
insert into #HourlyData_Counts
values (55,89,78,77,67,99,45,33,23,91)
select * from #HourlyData_Counts
SELECT hours,hour1, RANK() OVER (order by hour1 desc) as RANK
FROM
(
SELECT Hr_1, Hr_2, Hr_3, Hr_4, Hr_5, Hr_6, Hr_7, Hr_8, Hr_9, Hr_10
FROM #HourlyData_Counts
) as s
UNPIVOT
(
hour1
FOR hours IN
(
Hr_1,Hr_2,Hr_3,Hr_4,Hr_5,Hr_6,Hr_7,Hr_8,Hr_9,Hr_10
)
)AS pvt
order by hours

You can use the UNPIVOT for this, so your query shoud look like this
SELECT hr,counts, RANK() OVER(ORDER BY counts DESC) FROM
(SELECT * FROM #HourlyData_Counts) p
UNPIVOT
(counts FOR hr IN (Hr_1 ,Hr_2 ,Hr_3 ,Hr_4 ,Hr_5 ,Hr_6 ,Hr_7 , Hr_8 ,Hr_9 , Hr_10 ) )AS unpvt;
RESULT
Hr_6 99 1
Hr_10 91 2
Hr_2 89 3
Hr_3 78 4
Hr_4 77 5
Hr_5 67 6
Hr_1 55 7
Hr_7 45 8
Hr_8 33 9
Hr_9 23 10

If the number of columns and names of the columns are fixed, then you can use
;with r(hr, data_count) as (
select 'hr_1', hr_1 from #HourlyData_Counts union all
select 'hr_2', hr_2 from #HourlyData_Counts union all
select 'hr_3', hr_3 from #HourlyData_Counts union all
select 'hr_4', hr_4 from #HourlyData_Counts union all
select 'hr_5', hr_5 from #HourlyData_Counts union all
select 'hr_6', hr_6 from #HourlyData_Counts union all
select 'hr_7', hr_7 from #HourlyData_Counts union all
select 'hr_8', hr_8 from #HourlyData_Counts union all
select 'hr_9', hr_9 from #HourlyData_Counts union all
select 'hr_10', hr_10 from #HourlyData_Counts
)
select hr, data_count, data_rank = ROW_NUMBER() over(order by data_count asc)
from r
order by data_count

Related

Return random value for each row from different table

I'm trying to get random name for each row, but it just shows same random value for every row. What am I missing?
SELECT TOP (1000) v.id,v.[Name], RandomName
FROM [V3_Priva].[dbo].[Vehicle] v
cross join
(Select top 1 ISNULL([Description_cs-CZ], [Description]) RandomName
from crm.Enumeration e
join crm.EnumerationType et on e.EnumerationType_FK = et.Id
where EnumerationType_FK = 12
order by NEWID()) RandomName
Result table
Try using something like the following to drive your lookup.
DECLARE #Rows AS TABLE ( I INT NOT NULL )
DECLARE #Vals AS TABLE ( ID INT IDENTITY, Val NVARCHAR(255) NOT NULL )
INSERT INTO #Rows
VALUES ( 0 )
, ( 1 )
, ( 2 )
, ( 3 )
, ( 4 )
, ( 5 )
, ( 6 )
, ( 7 )
, ( 8 )
, ( 9 )
INSERT INTO #Vals
VALUES ( 'Apple' )
, ( 'Banana' )
, ( 'Peach' )
, ( 'Plum' )
, ( 'Pear' )
WITH cte AS ( SELECT *, ABS(CHECKSUM(NEWID())) % 5 ID FROM #Rows )
SELECT cte.I
, cte.ID
, V.ID
, V.Val
FROM cte
JOIN #Vals V ON V.ID = cte.ID + 1
ORDER BY I
This way new ID is generated for each row, rather than once for the lookup.

INSERT INTO #tmp from CTE query

I want to be able to insert the results of this CTE query into a temp table so I can sum the Total column.
CREATE TABLE #tmp
(
SerialNumber NVARCHAR(50),
StartDateTime NVARCHAR(50),
EndDateTime NVARCHAR(50),
Total NVARCHAR(50)
)
;WITH cte1 AS
(
SELECT
*,
CASE
WHEN Temperature > #maxthreshold AND LAG(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) IS NULL THEN 1
WHEN Temperature <= #maxthreshold AND LEAD(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) > #maxthreshold THEN 1
WHEN Temperature <= #maxthreshold AND LAG(Temperature) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) > #maxthreshold THEN 1
END AS chg
FROM
[RawData]
WHERE
SerialNumber = #_Serial
AND CombineDateTime BETWEEN #_DateFrom AND #_DateTo
), cte2 AS
(
SELECT
*,
SUM(chg) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime) AS grp
FROM
cte1
)
INSERT INTO #tmp
SELECT
SerialNumber,
MIN(CombineDateTime) AS StartDateTime,
MAX(CombineDateTime) AS EndDateTime,
DATEDIFF(SECOND, MIN(CombineDateTime), MAX(CombineDateTime)) / 60.0 AS 'Total'
FROM
cte2
GROUP BY
SerialNumber, grp
HAVING
MAX(Temperature) > #maxthreshold)
SELECT *
FROM #tmp
DROP TABLE #tmp
I have tried putting the insert in various places, but it does not insert, I have tried the following answers. I am confused as to why the insert won't work as it is outside of the recursion.
Answer 1
Answer 2
TIA

Select row name with max date with grouping

For example:
create table #t
(
[ID] int,
[Date] date,
[Name] varchar(5)
)
insert into #t
values
(1, getdate(),'1-1'),
(2, dateadd(D,-10,getdate()),'2-1'),
(2, dateadd(D,-5,getdate()),'2-2'),
(1, dateadd(M,-1,getdate()),'1-2')
select * from #t
I need to select [Name] for each [ID] with max [Data].
Something like this:
select [1], [2]
from ( select ID, [Date] from #t ) y
pivot (
max(y.[Date])
for y.ID in ([1],[2])
) pvt;
Output:
1 2
2017-04-28 2017-04-23
but instead of [Date] i want to see [Name]
what i want to view
1 2
1-1 2-2
Please help. Thank you.
Please try the following code
create table #t
(
[ID] int,
[Date] date,
[Name] varchar(5)
)
insert into #t
values
(1, getdate(),'1-1'),
(2, dateadd(D,-10,getdate()),'2-1'),
(2, dateadd(D,-5,getdate()),'2-2'),
(1, dateadd(M,-1,getdate()),'1-2')
select [1], [2]
from ( select ID, [Name] from #t ) y
pivot (
max(y.[Name])
for y.ID in ([1],[2])
) pvt;
drop table #t
You can use row_nubmber() with date desc and pivot as below:
;with cte as (
select id, RowN = row_number() over (partition by id order by date desc), name from #t
) select * from
(select id, name from cte where rown = 1 ) s
pivot (max(name) for id in ([1],[2])) p
You can try the following :
SELECT [1], [2]
FROM (SELECT y.ID,
t.Name
FROM (SELECT ID,
MAX([Date]) AS [Date]
FROM #t
GROUP BY ID ) y
INNER JOIN #t t ON y.[Date] = t.[Date]
) x
PIVOT
(
MAX(x.Name)
FOR x.ID IN ([1],[2])
) pvt;
You can see this here -> http://rextester.com/ZGQGSC94965
Hope this helps!!!
try this one.
CREATE TABLE #t
(
[ID] INT ,
[Date] DATE ,
[Name] VARCHAR(5)
)
INSERT INTO #t
VALUES (1, getdate(),'1-1'),
(2, dateadd(D,-10,getdate()),'2-1'),
(2, dateadd(D,-5,getdate()),'2-2'),
(1, dateadd(M,-1,getdate()),'1-2')
SELECT *
FROM #t;
WITH CTE
AS ( SELECT ID ,
MAX(Date) [Date]
FROM #t
GROUP BY ID
),
CTE2
AS ( SELECT cte.ID ,
cte.Date ,
t.name
FROM CTE
OUTER APPLY ( SELECT TOP 1
name
FROM #t
WHERE (ID = cte.ID AND Date = cte.Date)
) T
)
SELECT MAX([1]) [1] ,
MAX([2]) [2]
FROM ( SELECT ID ,
[Date] ,
NAME
FROM CTE2
) y PIVOT ( MAX(y.NAME) FOR y.ID IN ( [1], [2] ) ) pvt
Result
ID Date Name
----------- ---------- -----
1 2017-05-02 1-1
2 2017-04-22 2-1
2 2017-04-27 2-2
1 2017-04-02 1-2
(4 row(s) affected)
1 2
----- -----
1-1 2-2
(1 row(s) affected)

SQL query when result is empty

I have a table like this
USER itemnumber datebought (YYYYmmDD)
a 1 20160101
b 2 20160202
c 3 20160903
d 4 20160101
Now I have to show the total number of items bought by each user after date 20160202 (2 february 2016)
I used
SELECT USER, COUNT(itemnumber)<br/>
FROM TABLE<br/>
WHERE datebought >= 20160202<br/>
GROUP BY USER<br>
It gives me results
b 1
c 1
but I want like this
a 0
b 1
c 1
d 0
Please tell me what is the most quick method / efficient method to do that ?
Try like this,
DECLARE #table TABLE
(
[USER] VARCHAR(1),
itemnumber INT,
datebought DATE
)
INSERT INTO #TABLE VALUES
('a',1,'20160101'),
('b',2,'20160202'),
('b',2,'20160202'),
('b',2,'20160202'),
('c',3,'20160903'),
('d',4,'20160101')
SELECT *
FROM #TABLE
SELECT [USER],
Sum(CASE
WHEN datebought >= '20160202' THEN 1
ELSE 0
END) AS ITEMCOUNT
FROM #TABLE
GROUP BY [USER]
Use this
SELECT USER, COUNT(itemnumber)
FROM TABLE
WHERE datebought >= 20160202
GROUP BY USER
Though this query won't be a good idea for the large amount of data:
SELECT USER, COUNT(itemnumber)
FROM TABLE
WHERE datebought >= 20160202
GROUP BY USER
UNION
SELECT DISTINCT USER, 0
FROM TABLE
WHERE datebought < 20160202
USE tempdb
GO
DROP TABLE test1
CREATE TABLE test1(a NVARCHAR(10), ino INT, datebought INT)
INSERT INTO dbo.test1
( a, ino, datebought )
VALUES ( 'a' , 1 , 20160101)
INSERT INTO dbo.test1
( a, ino, datebought )
VALUES ( 'b' , 2 , 20160202)
INSERT INTO dbo.test1
( a, ino, datebought )
VALUES ( 'c' , 3 , 20160903)
INSERT INTO dbo.test1
( a, ino, datebought )
VALUES ( 'd' , 4 , 20160101)
SELECT * FROM dbo.test1
SELECT a, COUNT(ino) OVER(PARTITION BY a) FROM dbo.test1
WHERE datebought>=20160202
UNION ALL
SELECT a, 0 FROM dbo.test1
WHERE datebought<20160202
ORDER BY a

How to replace the 'Strings' with numerical values based on a group by clause

I have the below table (#temp1) where I need to replace the string in the column'Formula' with the matching input 'VALUE' column based on the group 'Yearmonth'.
The 'Formula' column may be of any mathematical expression for better understanding I have mentioned a simple example below.
IDNUM formula INPUTNAME VALUE YEARMONTH
---------------------------------------------------------------------
1 imports(398)+imports(399) imports(398) 17.000 2003:1
2 imports(398)+imports(399) imports(398) 56.000 2003:2
3 imports(398)+imports(399) imports(399) 15.000 2003:1
4 imports(398)+imports(399) imports(399) 126.000 2003:2
For eg :From the above table i need the output as
Idnum Formula Yearmonth
1. 17.00 +15.00 2003:1
2. 56.00 +126.00 2003:2
I tried with the below different query from various suggestions but coludnt achieve it. Could someone help me this out ?
Type1 :
SELECT
REPLACE(FORMULA, INPUTName, AttributeValue) AS realvalues,
yearmonth
FROM #temp1
GROUP BY yearmonth
TYPE2 :
USING XML PATH... In this case it got worked but I need to replace only the strings with the values and not to stuff the strings based on mathematcal operation.(Because the formula might be of any type).
SELECT
IDNUM = MIN(IDNUM),
FORMULA =
(SELECT STUFF(
(SELECT ' +' + CONVERT(VARCHAR(10), Value)
FROM #temp1
WHERE YEARMONTH = t1.YEARMONTH
FOR XML PATH(''))
,1, 2, '')),
YEARMONTH
FROM #TEMP1 t1
GROUP BY YEARMONTH
TYPE3:Using Recursions...This is returning only the null values...
;with t as (
select t.*,
row_number() over (partition by yearmonth order by idnum) as seqnum,
count(*) over (partition by yearmonth) as cnt
from #temp1 t
)
,cte as (
select t.seqnum, t.yearmonth, t.cnt,
replace(formula, inputname, AttributeValue) as formula1
from t
where seqnum = 1
union all
select cte.seqnum, cte.yearmonth, cte.cnt,
replace(CTE.formula1, T.inputname, T.AttributeValue) as formula2
from cte join
t
on cte.yearmonth = t.yearmonth
AND cte.seqnum = t.seqnum + 1
)
select row_number() over (order by (select null)) as id,formula1
from cte
where seqnum = cnt
This is full working example using recursive CTE:
DECLARE #DataSource TABLE
(
[IDNUM] TINYINT
,[formula] VARCHAR(MAX)
,[INPUTNAME] VARCHAR(128)
,[VALUE] DECIMAL(9,3)
,[YEARMONTH] VARCHAR(8)
);
INSERT INTO #DataSource ([IDNUM], [formula], [INPUTNAME], [VALUE], [YEARMONTH])
VALUES ('1', 'imports(398)+imports(399)', 'imports(398)', '17.000', '2003:1')
,('2', 'imports(398)+imports(399)', 'imports(398)', '56.000', '2003:2')
,('3', 'imports(398)+imports(399)', 'imports(399)', '15.000', '2003:1')
,('4', 'imports(398)+imports(399)', 'imports(399)', '126.000', '2003:2')
,('5', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(391)', '5.000', '2003:3')
,('6', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(392)', '10.000', '2003:3')
,('7', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(393)', '3.000', '2003:3')
,('8', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(394)', '-5.000', '2003:3');
WITH DataSource AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY [YEARMONTH] ORDER BY [IDNUM]) AS [ReplacementOrderID]
,[YEARMONTH]
,[formula]
,[INPUTNAME] AS [ReplacementString]
,[VALUE] AS [ReplacementValue]
FROM #DataSource
),
RecursiveDataSource AS
(
SELECT [ReplacementOrderID]
,[YEARMONTH]
,REPLACE([formula], [ReplacementString], [ReplacementValue]) AS [formula]
FROM DataSource
WHERE [ReplacementOrderID] = 1
UNION ALL
SELECT DS.[ReplacementOrderID]
,DS.[YEARMONTH]
,REPLACE(RDS.[formula], DS.[ReplacementString], DS.[ReplacementValue]) AS [formula]
FROM RecursiveDataSource RDS
INNER JOIN DataSource DS
ON RDS.[ReplacementOrderID] + 1 = DS.[ReplacementOrderID]
AND RDS.[YEARMONTH] = DS.[YEARMONTH]
)
SELECT RDS.[YEARMONTH]
,RDS.[formula]
FROM RecursiveDataSource RDS
INNER JOIN
(
SELECT [YEARMONTH]
,MAX([ReplacementOrderID]) AS [ReplacementOrderID]
FROM DataSource
GROUP BY [YEARMONTH]
) DS
ON RDS.[YEARMONTH] = DS.[YEARMONTH]
AND RDS.[ReplacementOrderID] = DS.[ReplacementOrderID]
ORDER BY RDS.[YEARMONTH]
Generally, you simply want to perform multiple replacements over a string in one statement. You can have many replacement values, just play with the MAXRECURSION option.
--Create sample data
DROP TABLE #temp1
CREATE TABLE #temp1 (IDNUM int, formula varchar(max), INPUTNAME varchar(max), VALUE decimal, YEARMONTH varchar(max))
INSERT INTO #temp1 VALUES
(1, 'imports(398)+imports(399)', 'imports(398)', 17.000, '2003:1'),
(2, 'imports(398)+imports(399)', 'imports(398)', 56.000, '2003:2'),
(3, 'imports(398)+imports(399)', 'imports(399)', 15.000, '2003:1'),
(4, 'imports(398)+imports(399)', 'imports(399)', 126.000, '2003:2')
--Query
;WITH t as (
SELECT formula, YEARMONTH, IDNUM
FROM #temp1
UNION ALL
SELECT REPLACE(a.formula, b.INPUTNAME, CAST(b.VALUE AS varchar(100))) AS formula, a.YEARMONTH, a.IDNUM
FROM t a
JOIN #temp1 b ON a.YEARMONTH = b.YEARMONTH AND a.formula LIKE '%' + b.INPUTNAME + '%'
)
SELECT MIN(IDNUM) AS IDNUM, formula, YEARMONTH
FROM t
WHERE formula not LIKE '%imports(%'
GROUP BY formula, YEARMONTH