sql pulling data in in certain rows but not others - sql

table 1 looks like this:
filekey hourstype hours
123 1 40
123 2 5
123 3 6
123 4 7
123 5 8
needed output should look like this:
filekey hours1 hours2 otherhourstype otherhourstotal
123 40 5 '' ''
123 '' '' 3 6
123 '' '' 4 7
123 '' '' 5 8
hours1 and hours2 occupy the same row, all other hours occupy their own row
there is one other possible format that can work:
filekey hours1 hours2 difhrstype difhrstotal difhourstype difhrstotal
123 40 5 3 6 4 7
in this scenario start with lowest hours type, then total extended through columns instead of rows with one row per filekey. I'm not sure how to make this one happen either. especially because there can be up to 8 hourstypes each of which may or may not exist for a given filekey

Try this for scenario 1:
CREATE TABLE #TMP(filekey INT, hourstype INT, [hours] INT)
INSERT INTO #TMP VALUES
(123,1,40)
,(123,2,5)
,(123,3,6)
,(123,4,7)
,(123,5,8)
SELECT
T.filekey
,SUM(CASE WHEN hourstype = 1 THEN [hours] ELSE 0 END) AS hours1
,SUM(CASE WHEN hourstype = 2 THEN [hours] ELSE 0 END) AS hours2
,CASE WHEN hourstype > 2 THEN [hourstype] ELSE 0 END AS otherhourstype
,CASE WHEN hourstype > 2 THEN [hours] ELSE 0 END AS otherhourstotal
FROM
#TMP T
GROUP BY
T.filekey
,CASE WHEN hourstype > 2 THEN [hourstype] ELSE 0 END
,CASE WHEN hourstype > 2 THEN [hours] ELSE 0 END

UNION a query that will produce the first row over a query that will produce the other three rows.
Hard-code the NULLs (or blanks or whatever you want) for the unused columns in each query.

Try the following:
select
pivottable.filekey,
[1] as hours1,
[2] as hours2,
[3] as hours3,
[4] as hours4,
[5] as hours5,
[6] as hours6,
[7] as hours7,
[8] as hours8
from table1
PIVOT (
sum(hours)
FOR hourstype IN ([1],[2],[3],[4],[5],[6],[7],[8])
) as pivottable

Related

Case Count not returning expected information

I have an automated check script for each morning where the user will be informed of the current number of jobs running as long as they don't fall into the category of "expected running jobs".
I would expected StatusID to be GREEN for IMPORT and AMBER for BATCH due to the current counts being 4 and 3 respectivley
My current code is
DECLARE #Datecreated DATETIME = GetDate())
DECLARE #JobInfo AS TABLE
(
JobType INT,
JobID NVARCHAR(30),
StatusID NVARCHAR(30),
Message NVARCHAR(500),
DateCreated DATETIME,
ITEMS INT
)
INSERT INTO #JobInfo (JobType,JobID,StatusID,Message, DateCreated,ITEMS)
SELECT
0 as Jobtype,
'BATCH' AS JobID,
CASE WHEN Count(CASE JobTypeID WHEN 1 THEN 0 WHEN 30 THEN 0 WHEN 234 THEN 0 ELSE 1 end) >0 THEN N'AMBER' ELSE N'GREEN' END,
'Jobs running longer than 1 hour (ITEMS)',
CAST( #DateCreated AS NVARCHAR(30)),
COUNT(CASE JobTypeID WHEN 1 THEN 0 WHEN 30 THEN 0 WHEN 234 THEN 0 ELSE 1 end)
FROM BATCH.dbo.JOB (NOLOCK) WHERE StatusID = 3
AND JobTypeID NOT IN (1,30,4005)
INSERT INTO #JobInfo (JobType,JobID,StatusID,Message, DateCreated,ITEMS)
SELECT
0 as Jobtype,
'IMPORT' AS JobID,
CASE WHEN Count(CASE JobTypeID WHEN 191 THEN 0 WHEN 124 THEN 0 WHEN 4005 THEN 0 ELSE 1 end) >0 THEN N'AMBER' ELSE N'GREEN' END,
'Jobs running longer than 1 hour (ITEMS)',
CAST( #DateCreated AS NVARCHAR(30)),
COUNT(CASE JobTypeID WHEN 191 THEN 0 WHEN 124 THEN 0 WHEN 4005 THEN 0 ELSE 1 end)
FROM IMPORT.dbo.JOB (NOLOCK) WHERE StatusID = 3
AND JobTypeID NOT IN (191,124,4005)
SELECT * FROM #JobInfo
However currently the StatusID is AMBER for both and the ITEMS are 2 and 4 respectively
SELECT * FROM BATCH.dbo.JOB (NOLOCK) WHERE StatusID = 3 --shows 4 rows, 30,1,1072,234
SELECT * FROM IMPORT.dbo.JOB (NOLOCK) WHERE StatusID = 3 --shows 3 rows, 4005,124,191
Could someone please help explain why this is the case?

How do I query a table in SQL to produce a result where column names are stacked vertically based on a condition?

Suppose I have a SQL table titled Users with the following example data:
Description Days
--------------------------
Healthy 10
High-blood pressure 20
Cholesterol 23
Diabetes 31
High-blood pressure 8
Healthy 12
Diabetes 18
Cholesterol 25
High-blood pressure 20
Healthy 6
How would I produce a result that looks like the following where the columns: Less_than_20_days, 20_days and Greater_than_20_days contains counts from the table above
Description Less_than_20_days 20_days Greater_than_20_days
-----------------------------------------------------------------------------------
Healthy 3 0 0
High-blood pressure 1 2 0
Cholesterol 0 0 2
Diabetes 1 0 1
I'm trying to get this to work in SQL Server and have tried using the union operator, temp tables and ctes but I can't seem to get the desired result.
Any help would be much appreciated!
You can combine case with sum():
select
[Description]
,sum(case when [Days] < 20 then 1 else 0 end) as Less_than_20_days
,sum(case when [Days] = 20 then 1 else 0 end) as d20_days
,sum(case when [Days] > 20 then 1 else 0 end) as Greater_than_20_days
from users
group by [Description]
Use conditional aggregation:
select description,
sum(case when days < 20 then 1 else 0 end) as num_lt_20,
sum(case when days = 20 then 1 else 0 end) as num_eq_20,
sum(case when days > 20 then 1 else 0 end) as num_gt_20
from t
group by description

PIVOT values from two columns to multiple columns

Table: Sample
ID Day Status MS
----------------------------
1 1 0 10
1 2 0 20
1 3 1 15
2 3 1 3
2 30 0 5
2 31 0 6
Expected Result:
ID Day1 Day2 Day3....Day30 Day31 Status1 Status2 Status3...Status30 Status31
---------------------------------------------------------------------------------------
1 10 20 15 NULL NULL 0 0 1 NULL NULL
2 NULL NULL 3 5 6 NULL NULL 1 0 0
I want to get the MS and Status value for each day from 1 to 31 for each ID.
I have used PIVOT to get the below result.
Result:
ID Day1 Day2 Day3....Day30 Day31
-------------------------------------
1 10 20 15 NULL NULL
2 NULL NULL 3 5 6
Query:
SELECT
ID
,[1] AS Day1
,[2] AS Day2
,[3] AS Day3
.
.
.
,[30] AS Day30
,[31] AS Day31
FROM
(
SELECT
ID
,[Day]
,MS
FROM
Sample
) AS A
PIVOT
(
MIN(MS)
FOR [Day] IN([1],[2],[3],...[30],[31])
) AS pvtTable
How can I merge the Status column with the result?.
Try this. Use Another Pivot to transpose Status column. Then use aggregate (Max or Min) in select column list with group by Id to get the Result.
CREATE TABLE #est
(ID INT,[Day] INT,[Status] INT,MS INT)
INSERT #est
VALUES (1,1,0,10),(1,2,0,20),(1,3,1,15 ),
(2,3,1,3),(2,30,0,5),(2,31,0,6)
SELECT ID,
Max([Day1]) [Day1],
Max([Day2]) [Day2],
Max([Day3]) [Day3],
Max([Day30]) [Day30],
Max([Day31]) [Day31],
Max([status1]) [status1],
Max([status2]) [status2],
Max([status3]) [status3],
Max([status30])[status30],
Max([status31])[status31]
FROM (SELECT Id,
'status' + CONVERT(VARCHAR(30), Day) col_stat,
'Day' + CONVERT(VARCHAR(30), Day) Col_Day,
[status],
ms
FROM #est) a
PIVOT (Min([ms])
FOR Col_Day IN([Day1],[Day2],[Day3],[Day30],[Day31])) piv
PIVOT (Min([status]) FOR col_stat IN ([status1],[status2],[status3],[status30],[status31])) piv1
GROUP BY id

How do I calculate values across three columns for a given formula?

I am using SQL Server 2000. I am trying to calculate Net Promoter Score or NPS based on the below formula
Formula: (Promoters - Detractors) / Total Questions
Scores 9 - 10 are considered promoters.
Scores 0 - 6 are considered detractors.
Scores 7 - 8 are considered neutral.
I have the following data:
Time Q1 Q2 Q3
----------- ------ ------ ------
2012-03-14 7 7 5
2012-03-15 3 2 5
2012-03-15 7 NA 2
2012-03-15 9 10 NULL
2012-03-15 8 4 4
2012-03-15 NA 6 4
2012-03-16 1 7 4
2012-03-16 NULL 0 5
2012-03-17 9 9 2
2012-03-19 0 0 1
2012-03-19 8 5 4
2012-03-19 1 0 3
The person who originally wrote the database stored NULL values as blanks or NA enter code herein a NVARCHAR format (only god knows why..) so the query I am playing with now uses a ISNUMERIC and im trying not to count blank or NA values.
My query, which doesnt work properly looks like:
SELECT CAST(SUM(CASE WHEN ISNUMERIC([Q1]) != 1 THEN 0
WHEN CAST([Q1] AS int) >= 9 THEN 1
WHEN CAST([Q1] AS int) <= 6 THEN -1
ELSE 0 END)
+ SUM(CASE WHEN ISNUMERIC([Q2]) != 1 THEN 0
WHEN CAST([Q2] AS int) >= 9 THEN 1
WHEN CAST([Q2] AS int) <= 6 THEN -1
ELSE 0 END)
+ SUM(CASE WHEN ISNUMERIC([Q3]) != 1 THEN 0
WHEN CAST([Q3] AS int) >= 9 THEN 1
WHEN CAST([Q3] AS int) <= 6 THEN -1
ELSE 0 END)
AS FLOAT)
/ (SUM(CASE WHEN ISNUMERIC([Q1]) != 1 THEN 0
ELSE 1 END)
+ SUM(CASE WHEN ISNUMERIC([Q2]) != 1 THEN 0
ELSE 1 END)
+ SUM(CASE WHEN ISNUMERIC([Q3]) != 1 THEN 0
ELSE 1 END)
) as [NPS]
FROM [nps]
Can someone point me in the right direction?
Thanks!
As others pointed out, changing the data type of the column from NVARCHAR to INT would be ideal.
Here is the query that might help you get the result that you need.
Click here to view the demo in SQL Fiddle using SQL Server 2012
Script:
SELECT
(
SUM (CASE WHEN q >= 9 THEN 1. END) -
SUM (CASE WHEN q <= 6 THEN 1. END)
) /
SUM (1.) AS nps
FROM
(
SELECT (CASE
WHEN ISNUMERIC(q1) <> 1 THEN 0.
ELSE CAST(q1 AS FLOAT)
END) AS q
FROM [nps]
UNION ALL
SELECT (CASE
WHEN ISNUMERIC(q2) <> 1 THEN 0.
ELSE CAST(q2 AS FLOAT)
END) AS q
FROM [nps]
UNION ALL
SELECT (CASE
WHEN ISNUMERIC(q3) <> 1 THEN 0.
ELSE CAST(q3 AS FLOAT)
END) AS q
FROM [nps]
) nps;
Output:
np
---------
-0.611111
How about fixing the database? Is there a case when NA or blank is misrepresented if the value is actually 0? If not, convert all the blanks and NA's to 0, change the column datatype to int and not allow null. Then your life becomes much simpler.
Don't mess with CASTing your data types. Either change the schema, or deal with them natively.
SELECT
SUM(
CASE WHEN [Q1] IN ( '9', '10') THEN 1.0
WHEN [Q1] IN ('7', '8', 'NA') THEN 0.0
WHEN [Q1] IS NULL THEN 0.0
ELSE -1.0 END
+ CASE WHEN [Q2] IN ( '9', '10') THEN 1.0
WHEN [Q2] IN ('7', '8', 'NA') THEN 0.0
WHEN [Q2] IS NULL THEN 0.0
ELSE -1.0 END
+ CASE WHEN [Q3] IN ( '9', '10') THEN 1.0
WHEN [Q3] IN ('7', '8', 'NA') THEN 0.0
WHEN [Q3] IS NULL THEN 0.0
ELSE -1.0 END
)
/
SUM(
CASE WHEN [Q1] <> 'NA' THEN 1.0 ELSE 0.0 END
+ CASE WHEN [Q2] <> 'NA' THEN 1.0 ELSE 0.0 END
+ CASE WHEN [Q3] <> 'NA' THEN 1.0 ELSE 0.0 END
) AS [nps]
FROM
[nps]
The divisor is nice an simple; if the [Qn] value is NULL it fails the test and returns 0.0 :)
You can also simplify it even further, without changing the schema, by always using NULL instead of 'NA'.

SQl Server 2005: Rows to columns -- how to do this challenge?

Please let me know, How to convert the following data ,
[id] cost1 cost2 year
1 5 10 2010
1 4 15 2011
2 10 10 2010
into this format [rows of 'Year' to columns heading]
id [cost1-2010] [cost2-2010] [cost1-2011] [cost2-2011]
1 5 10 4 15
2 10 10 0 0
Use PIVOT
example: http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
try something like this:
DECLARE #YourTable table (id int, cost1 int, cost2 int, year int)
INSERT #YourTable VALUES (1,5,10,2010)
INSERT #YourTable VALUES (1,4,15,2011)
INSERT #YourTable VALUES (2,10,10,2010)
SELECT
id
,SUM(CASE WHEN year=2010 THEN cost1 else 0 END) AS "Cost1-2010"
,SUM(CASE WHEN year=2010 THEN cost2 else 0 END) AS "Cost2-2010"
,SUM(CASE WHEN year=2011 THEN cost1 else 0 END) AS "Cost1-2011"
,SUM(CASE WHEN year=2011 THEN cost2 else 0 END) AS "Cost2-2010"
FROM #YourTable
GROUP BY id
OUTPUT
id Cost1-2010 Cost2-2010 Cost1-2011 Cost2-2010
----------- ----------- ----------- ----------- -----------
1 5 10 4 15
2 10 10 0 0
(2 row(s) affected)
If you want to do this dynamically based on data, it is going to be more difficult than just using PIVOT. For PIVOT or the conditional sum technique
[2010Values] = ( SUM(Case when year = 2010 then FieldValue Else 0 End)
you must know the column name ahead of time.
If you wish to set column names dynamically based on the data received then you'll have to go the dynamic SQL route which can get ugly.
Check out the discussion on this post. That should have you dialed.