Count Distinct Values FROM Column - sql

I have Written a query which returns multiple column.Out of which One Column contains repetitive entries.
FAULT_SHORT_NAME
ATM DOWN DUE TO LINK PROBLEM
ATM DOWN DUE TO LINK PROBLEM
ALL CASSETTES FAULTED
ALL CASSETTES FAULTED
ATM IS MARK DOWN
ATM IS MARK DOWN
Now I want to Modify My query in Such a way that it will show me Value Count as
ATM DOWN DUE TO LINK PROBLEM ALL CASSETTES FAULTED ATM IS MARK DOWN
2 2 2
There Can be Different "FAULT_SHORT_NAME" Values so Cant Hard Code them.My Original Query is
Select * From ATMStatus S Left Join ATM A on S.ATM=A.Code
Left Join EventMsg E On S.Fault=E.Code
Where A.ATMStatus=0 AND S.TicketBooked <> 0
FAULT_SHORT_NAME is Column of Table "EventMsg"

It looks like you want a PIVOT since you want the values as columns instead of rows. there are two ways to do this either a Static or dynamic pivot.
Static Pivot, you hard-code the values of the columns:
SELECT *
FROM
(
Select *
From ATMStatus S
Left Join ATM A
on S.ATM=A.Code
Left Join EventMsg E
On S.Fault=E.Code
Where A.ATMStatus=0
AND S.TicketBooked <> 0
) x
PIVOT
(
count(*)
for FAULT_SHORT_NAME in ([ATM DOWN DUE TO LINK PROBLEM],
[ALL CASSETTES FAULTED], [ATM IS MARK DOWN])
) p
Dynamic Pivot, the columns are generated at run-time:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(FAULT_SHORT_NAME)
from EventMsg
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'SELECT ' + #cols + ' from
(
Select *
From ATMStatus S
Left Join ATM A
on S.ATM=A.Code
Left Join EventMsg E
On S.Fault=E.Code
Where A.ATMStatus=0
AND S.TicketBooked <> 0
) x
pivot
(
count(*)
for FAULT_SHORT_NAME in(' + #cols + ')
) p '
execute(#query)
Both will produce the same results. If you provide additional details about the tables and some sample data, then I could provide a more exact example.

Related

SQL dynamic unpivot table as function

I currently have a query which I am using to unpivot an existing table.
Some background information on the table - each year a new column is added to the table to indicate the $ values for a project ID for that year. With every column added one will be dropped. All these columns are prefixed with 'YR_' followed by the new year. There are constantly 20 'YR_' columns.
I am required to unpivot the 'YR_' columns so that they appear as per below, allowing me to utilize the information easier for several reports -
Before unpivot -
ProjectID YR_16 YR_17 YR_18 YR_19 YR_20
10 0 100 20 25 100
After unpivot -
ProjectID YR Value
10 YR_16 0
10 YR_17 100
10 YR_18 20
10 YR_19 25
10 YR_20 100
Below is the query I am using to create the unpivot table, which will dynamically pick up columns as they are added/dropped
declare #query as NVARCHAR(max);
Declare #cols as NVARCHAR(250) = STUFF((
Select distinct ',' + QUOTENAME(Column_Name)
From INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = 'F1BWK_PLM_CAPEX'
And COLUMN_NAME like 'YR_%'
For XML Path(''), type)
.value('.','NVARCHAR(MAX)')
,1,1,'');
Select #query = 'With Unpivoted as
(
Select * from F1BWK_PLM_CAPEX U
Unpivot (
Val
For Yr in (' + #cols + ')
)
As UnpivotTable
)
Select U.*
From Unpivoted U
inner join [dbo].[F1_SYPAR_CTL] CTL
on CTL.value = U.WS_VERS
and CTL.PARAM_NAME like ''MBRC_CURR_PLM_BUDVER''
inner join [dbo].[F1_SYPAR_CTL] CTL2
on CTL2.value = U.WS_NAME
and CTL2.PARAM_NAME like ''MBRC_CURR_PLM_BUDWSH''';
Exec(#query);
I am having issues in turning this query into a function so that I can call upon it and save it in SQL Server so that other members of my team can use it when they require it.
This is my first time using unpivot tables and creating functions. Open to suggestions on changing my dynamic unpivot query to best suits my needs.
Thanks in advance
In SQL Server you are not allowed to have dynamic SQL in functions.
You can create an SP that will return a record set generated using your code above.
UPDATE:
For the sake of completeness:
You can also call the above SP using (OPENQUERY) which would allow you to join to other tables without having to save to a temp table first but IMO it is an ugly way do this.
END UPDATE:
Another way is to create a VIEW that would un-pivot this table and create an SP that would regenerate this view after the process that adds a new column is completed e.g.
CREATE TABLE F1BWK_PLM_CAPEX( Val INT, Yr_17 INT, Yr_18 INT )
INSERT INTO F1BWK_PLM_CAPEX
SELECT 1, 10, 12
CREATE VIEW F1BWK_PLM_CAPEX_UNPIVOTED
AS
SELECT *
FROM F1BWK_PLM_CAPEX AS U
UNPIVOT (
Val2 FOR Yr IN (Yr_17, Yr_18)
)
AS UnpivotTable;
CREATE PROCEDURE dbo.Create_F1BWK_PLM_CAPEX_UNPIVOTED
AS
SET NOCOUNT ON
DECLARE #query as NVARCHAR(max);
DECLARE #cols as NVARCHAR(250) =
STUFF((
SELECT distinct ',' + QUOTENAME( Column_Name )
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'F1BWK_PLM_CAPEX'
AND COLUMN_NAME like 'YR_%'
For XML Path(''), type)
.value('.','NVARCHAR(MAX)' )
,1,1,'');
SELECT #query = '
ALTER VIEW F1BWK_PLM_CAPEX_UNPIVOTED
AS
SELECT *
FROM F1BWK_PLM_CAPEX AS U
UNPIVOT (
Val2 FOR Yr IN ( ' + #cols + ' )
)
AS UnpivotTable
';
EXEC(#query);
RETURN;
Now your query would become this:
SELECT *
FROM F1BWK_PLM_CAPEX_UNPIVOTED AS U
INNER JOIN [dbo].[F1_SYPAR_CTL] AS CTL
ON CTL.value = U.WS_VERS and CTL.PARAM_NAME = 'MBRC_CURR_PLM_BUDVER'
INNER JOIN [dbo].[F1_SYPAR_CTL] AS CTL2
ON CTL2.value = U.WS_NAME AND CTL2.PARAM_NAME = 'MBRC_CURR_PLM_BUDWSH'
At the end of the year a process runs that adds a new column:
ALTER TABLE F1BWK_PLM_CAPEX
ADD Yr_19 INT NOT NULL DEFAULT( 10 )
This process needs to run this SP to regenerate the view:
EXEC Create_F1BWK_PLM_CAPEX_UNPIVOTED
Notes:
I have replaced LIKE with = as your query matches on a full value. Only use LIKE when you need to specify wild cards.
I have also fixed a syntax error by changing Val to Val2 in the UNPIVOT query

SQL Pivot Convert Null to 0 [duplicate]

I tried to convert the (null) values with 0 (zeros) output in PIVOT function but have no success.
Below is the table and the syntax I've tried:
SELECT
CLASS,
[AZ],
[CA],
[TX]
FROM #TEMP
PIVOT (SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])) AS PVT
ORDER BY CLASS
CLASS AZ CA TX
RICE 10 4 (null)
COIN 30 3 2
VEGIE (null) (null) 9
I tried to use the ISNULL but did not work.
PIVOT SUM(ISNULL(DATA,0)) AS QTY
What syntax do I need to use?
SELECT CLASS,
isnull([AZ],0),
isnull([CA],0),
isnull([TX],0)
FROM #TEMP
PIVOT (SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])) AS PVT
ORDER BY CLASS
If you have a situation where you are using dynamic columns in your pivot statement you could use the following:
DECLARE #cols NVARCHAR(MAX)
DECLARE #colsWithNoNulls NVARCHAR(MAX)
DECLARE #query NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(Name)
FROM Hospital
WHERE Active = 1 AND StateId IS NOT NULL
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #colsWithNoNulls = STUFF(
(
SELECT distinct ',ISNULL(' + QUOTENAME(Name) + ', ''No'') ' + QUOTENAME(Name)
FROM Hospital
WHERE Active = 1 AND StateId IS NOT NULL
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
EXEC ('
SELECT Clinician, ' + #colsWithNoNulls + '
FROM
(
SELECT DISTINCT p.FullName AS Clinician, h.Name, CASE WHEN phl.personhospitalloginid IS NOT NULL THEN ''Yes'' ELSE ''No'' END AS HasLogin
FROM Person p
INNER JOIN personlicense pl ON pl.personid = p.personid
INNER JOIN LicenseType lt on lt.licensetypeid = pl.licensetypeid
INNER JOIN licensetypegroup ltg ON ltg.licensetypegroupid = lt.licensetypegroupid
INNER JOIN Hospital h ON h.StateId = pl.StateId
LEFT JOIN PersonHospitalLogin phl ON phl.personid = p.personid AND phl.HospitalId = h.hospitalid
WHERE ltg.Name = ''RN'' AND
pl.licenseactivestatusid = 2 AND
h.Active = 1 AND
h.StateId IS NOT NULL
) AS Results
PIVOT
(
MAX(HasLogin)
FOR Name IN (' + #cols + ')
) p
')
You cannot place the IsNull() until after the data is selected so you will place the IsNull() around the final value in the SELECT:
SELECT CLASS,
IsNull([AZ], 0) as [AZ],
IsNull([CA], 0) as [CA],
IsNull([TX], 0) as [TX]
FROM #TEMP
PIVOT
(
SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])
) AS PVT
ORDER BY CLASS
Sometimes it's better to think like a parser, like T-SQL parser. While executing the statement, parser does not have any value in Pivot section and you can't have any check expression in that section. By the way, you can simply use this:
SELECT CLASS
, IsNull([AZ], 0)
, IsNull([CA], 0)
, IsNull([TX], 0)
FROM #TEMP
PIVOT (
SUM(DATA)
FOR STATE IN (
[AZ]
, [CA]
, [TX]
)
) AS PVT
ORDER BY CLASS
You have to account for all values in the pivot set. you can accomplish this using a cartesian product.
select pivoted.*
from (
select cartesian.key1, cartesian.key2, isnull(relationship.[value],'nullvalue') as [value]
from (
select k1.key1, k2.key2
from ( select distinct key1 from relationship) k1
,( select distinct key2 from relationship) k2
) cartesian
left outer join relationship on relationship.key1 = cartesian.key1 and relationship.key2 = carterisan.key2
) data
pivot (
max(data.value) for ([key2_v1], [key2_v2], [key2_v3], ...)
) pivoted
To modify the results under pivot, you can put the columns in the selected fields and then modify them accordingly. May be you can use DECODE for the columns you have built using pivot function.
Kranti A
I have encountered a similar problem. The root cause is that (use your scenario for my case), in the #temp table, there is no record for:
a. CLASS=RICE and STATE=TX
b. CLASS=VEGIE and (STATE=AZ or STATE=CA)
So, when MSSQL does pivot for no record, MSSQL always shows NULL for MAX, SUM, ... (aggregate functions).
None of above solutions (IsNull([AZ], 0)) works for me, but I do get ideas from these solutions.
Sorry, it really depends on the #TEMP table. I can only provide some suggestions.
Make sure #TEMP table have records for below condition, even Data is null.
a. CLASS=RICE and STATE=TX
b. CLASS=VEGIE and (STATE=AZ or STATE=CA)
You may need to use cartesian product: select A.*, B.* from A, B
In the select query for #temp, if you need to join any table with WHERE, then would better put where inside another sub select query. (Goal is 1.)
Use isnull(DATA, 0) in #TEMP table.
Before pivot, make sure you have achieved Goal 1.
I can't give an answer to the original question, since there is no enough info for #temp table. I have pasted my code as example here.
SELECT * FROM (
SELECT eeee.id as enterprise_id
, eeee.name AS enterprise_name
, eeee.indicator_name
, CONVERT(varchar(12) , isnull(eid.[date],'2019-12-01') , 23) AS data_date
, isnull(eid.value,0) AS indicator_value
FROM (select ei.id as indicator_id, ei.name as indicator_name, e.* FROM tbl_enterprise_indicator ei, tbl_enterprise e) eeee
LEFT JOIN (select * from tbl_enterprise_indicator_data WHERE [date]='2020-01-01') eid
ON eeee.id = eid.enterprise_id and eeee.indicator_id = enterprise_indicator_id
) AS P
PIVOT
(
SUM(P.indicator_value) FOR P.indicator_name IN(TX,CA)
) AS T

Change Rows to Columns in SQL Server

I've been working on this query for an hour and half but I can't get it done,
First, this is my query:
SELECT
Questions, PossibleAnswer,
((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(SELECT
A.AnswerID, B.Questions, B.QuestionID, C.PossibleAnswer
FROM
TblSurveyCustomerAnswers A
INNER JOIN
TblSurveyQuestion B ON A.QuestionID = B.QuestionID
INNER JOIN
TblSurveyAnswer C ON A.AnswerID = C.AnswerID
WHERE
A.CustomerID = 1) AS SOURCE
GROUP BY
Questions, PossibleAnswer
The result is below:
Now, I want the rows for column name PossibleAnswer to be converted in columns, so I did a research and found the PIVOT command (I need dynamic since it's a possible answers field) and this is my code
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(PossibleAnswer)
FROM
(
SELECT DISTINCT X.*
FROM
(
SELECT Questions,PossibleAnswer, ((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(
SELECT A.AnswerID,B.Questions, B.QuestionID, C.PossibleAnswer
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
INNER JOIN TblSurveyAnswer C
ON A.AnswerID = C.AnswerID
WHERE A.CustomerID = 1
) AS SOURCE
GROUP BY Questions, PossibleAnswer
) X
) AS B
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
'SELECT Questions, ' + #ColumnName + '
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
PIVOT(Max(Questions)
FOR PossibleAnswer IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
And I can't get the pivot work, need help. I'm stuck. See this error:
In general for questions like these you should provide sample data, table definitions and expected output so people can take your script, fiddle with it and produce something that works. See How to post a T-SQL question on a public forum for one way to do this.
Since it is hard to look at a dynamic script, not having the table structures, and point at what your problem is, let me give you the following advice:
Instead of taking your big query that produces the output and form queries around that big query, first insert the output of that query into a temporary table. You can do this by placing an INTO #temp_table clause after the SELECT clause. This creates a new temporary table #temp_table containing the output of the query.
SELECT --your select columns
INTO #p_in -- creates a temporary table #p_in that contains the output
FROM --the rest of your query
Determine the pivot columns based on the newly created temporary table. It'll be a lot more conscise and easier to spot errors
Write your Dynamic SQL using the temporary table (again it'll be a lot more conscise and easier to spot errors)
Don't forget to DROP the temporary table after executing the dynamic SQL.
I just try to solved problem without temporary table. You may edit query as your requirement.
--For PIVOT column
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName ''''+ PossibleAnswer + '''' + ' , ' + #ColumnName
FROM
(
SELECT
DISTINCT PossibleAnswer
FROM
(
SELECT
A.AnswerID, B.Questions, B.QuestionID, C.PossibleAnswer
FROM
TblSurveyCustomerAnswers A
INNER JOIN
TblSurveyQuestion B ON A.QuestionID = B.QuestionID
INNER JOIN
TblSurveyAnswer C ON A.AnswerID = C.AnswerID
WHERE
A.CustomerID = 1
) AS SOURCE
)B
--For removing last comma
IF #ColumnName != ''
BEGIN
SET #ColumnName = SUBSTRING(#ColumnName, 1, LEN(#ColumnName)-1)
END
-- Make result
SELECT *
FROM
(
SELECT Questions,PossibleAnswer, ((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(
SELECT A.AnswerID,B.Questions, B.QuestionID, C.PossibleAnswer
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
INNER JOIN TblSurveyAnswer C
ON A.AnswerID = C.AnswerID
WHERE A.CustomerID = 1
) AS SOURCE
GROUP BY Questions, PossibleAnswer
)C
PIVOT
( Max(Questions)
FOR PossibleAnswer IN (#ColumnName)
) AS PVTTable

How do i join the rows into dynamic columns in this case? [duplicate]

This question already has an answer here:
Pivot Dynamic Columns, no Aggregation
(1 answer)
Closed 9 years ago.
I'm sorry to post this, what i feel, almost duplicate. But i've tried the solutions i've found but haven't gotten it to work in my solution :(
This is how the SQL looks before i FUBARed it. This returns the data in a pretty good format. But i get duplicate rows with the same data except that the questions and answers are changed. I'd like that the Question would be the column name and the answer it's value.
SELECT c.*, sa.Question, sa.Answer
FROM Customers as c, Surveys s, SurveyAnswers sa
WHERE c.OrderID IN(SELECT id FROM #orders)
AND s.CustomerID = c.id
AND sa.SurveyID = s.ID
My SQL is weak and i got to get this done asap :( The alternative is to do the more heavy lifting in the .net app but i'd be nice to get the data directly
Best regards,
Mikael
You want to use Bluefeet's answer here to accomplish a dynamic column pivot. (I've omitted your #orders filter for brevity):
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(sa.Question)
FROM SurveyAnswers sa
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT CustomerID, Name, ' + #cols + ' from
(
select
c.ID as CustomerId,
c.Name,
sa.Question,
sa.Answer
FROM Customers as c
INNER JOIN Surveys s ON s.CustomerID = c.id
INNER JOIN SurveyAnswers sa ON sa.SurveyID = s.ID
) x
pivot
(
min(Answer)
for Question in (' + #cols + ')
) p '
execute(#query);
SqlFiddle here

SQL: Is there a clever way to show text data in pivoted columns without having inner queries or aggregate functions?

I have a bunch of data (multiple rows for each unique reference) that needs to be in one row with multiple columns. Some of columns that need to be used have to be further split out as they hold more than one value. This has been done using an unpivot. I now have 7 columns from this 1 original column and it now needs to display statuses against the new 7 columns. I cannot however use a pivot as I need to see the various statuses in the 7 columns and not a min, max or a count.
You can perform this type of shift with a PIVOT function.
Static Pivot (See SQL Fiddle for Demo):
select *
from
(
select reference, jobtypesplit, status
from t1
) x
pivot
(
min(status)
for jobtypesplit in ([DDS], [MBN], [LPN], [WEN], [LLP], [OPE], [SSE])
) p
This can also be done dynamically (See SQL Fiddle)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(jobtypesplit)
FROM t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT reference, ' + #cols + ' from
(
select reference, jobtypesplit, status
from t1
) x
pivot
(
min(status)
for jobtypesplit in (' + #cols + ')
) p '
execute(#query)