Pivot Table with varchar values - sql-server

this is the first-time I use this and I hope i will achieve this, I am getting mad. I am still a newbie about all this programming with SQL thing, I am trying to use pivot table to turn the source table in the desired output showed as below.
This is my source table
Here is the image, I was unable to upload it (https://i.stack.imgur.com/KDStF.jpg).
But whatever I try it returns me numbers but the varchar values I would like to, as it is shown above.
Would any of you know how to achieve it?
I am using Transact SQL in Sql Server, here is my code
SELECT [Ques1], [Ques2]
FROM
(
SELECT
D.DocumentId,
DA.QuestionId,
Q.ShortText,
DA.[Text],
Q.SectionId,
1 as [Count]
-- ShortText is literally 'Ques1' or 'Ques2'
FROM Document D
INNER JOIN DocumentAnswer DA
ON DA.DocumentId = D.DocumentId
INNER JOIN Question Q
ON Q.QuestionId = DA.QuestionId
WHERE D.DeleteDate IS NULL
) d
PIVOT
(
Max(ShortText)
FOR [Text] IN ([Ques1], [Ques2])
) p

SQL Fiddle
MS SQL Server 2008 Schema Setup:
Query 1:
DECLARE #TABLE TABLE (DocID INT, Ques VARCHAR(100), Ans VARCHAR(100))
INSERT INTO #TABLE VALUES
(1 , 'Ques1' , 'Hola'),
(1 , 'Ques2' , 'Padr'),
(2 , 'Ques1' , 'Excue'),
(2 , 'Ques2' , 'Dir')
SELECT * FROM
( -- Put your existing query here
SELECT * FROM #TABLE
) t
PIVOT (MAX(Ans)
FOR Ques
IN ([Ques1],[Ques2])
)p
Results:
| DOCID | QUES1 | QUES2 |
|-------|-------|-------|
| 1 | Hola | Padr |
| 2 | Excue | Dir |

Related

Part Id 3900 take wrong technology id as 7 and it must Be 2 because Feature Name and Value Exist?

I work on sql server 2017 I have table #partsfeature already exist as below
create table #partsfeature
(
PartId int,
FeatureName varchar(300),
FeatureValue varchar(300),
TechnologyId int
)
insert into #partsfeature(PartId,FeatureName,FeatureValue,TechnologyId)
values
(1211,'AC','5V',1),
(2421,'grail','51V',2),
(6211,'compress','33v',3)
my issue Done For Part id 3900 it take wrong
Technology Id 7 and Correct Must be 2
Because Feature name and Feature Value Exist
So it Must Take Same TechnologyId Exist
on Table #partsfeature as Technology Id 2 .
correct will be as Below
+--------+--------------+---------------+-------------
| PartID | FeatureName | FeatureValue | TechnologyId
+--------+--------------+---------------+-------------
| 3900 | grail | 51V | 2
+--------+--------------+---------------+-------
what I try is
insert into #partsfeature(PartId,FeatureName,FeatureValue,TechnologyId)
select PartId,FeatureName,FeatureValue,
TechnologyId = dense_rank() over (order by FeatureName,FeatureValue)
+ (select max(TechnologyId) from #partsfeature)
from
(
values
(3900,'grail','51V',NULL),
(5442,'compress','30v',NULL),
(7791,'AC','59V',NULL),
(8321,'Angit','50V',NULL)
) s (PartId,FeatureName,FeatureValue,TechnologyId)
Expected Result For Parts Inserted
Use NOT EXISTS() to check for existance of FeatureName and FeatureValue.
Sub query to get existing maximum TechnologyId from table and row_number() to generate a running sequence
insert into #partsfeature(PartId,FeatureName,FeatureValue,TechnologyId)
select PartId,FeatureName,FeatureValue,
TechnologyId = row_number() over (order by PartId)
+ (select max(TechnologyId) from #partsfeature)
from
(
values
(3900,'grail','51V',NULL),
(5442,'compress','30v',NULL),
(7791,'AC','59V',NULL),
(8321,'Angit','50V',NULL)
) s (PartId,FeatureName,FeatureValue,TechnologyId)
where not exists
(
select *
from #partsfeature x
where x.FeatureName = s.FeatureName
and x.FeatureValue = s.FeatureValue
)

Simplify multiple joins

I have a Claims table with 70 columns, 16 of which contain diagnosis codes. The codes mean nothing, so I need to pull the descriptions for each code located in a separate table.
There has to be a simpler way of pulling these code descriptions:
-- This is the claims table
FROM
[database].[schema].[claimtable] AS claim
-- [StagingDB].[schema].[Diagnosis] table where the codes located
-- [ICD10_CODE] column contains the code
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag1 ON claim.[ICDDiag1] = diag1.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag2 ON claim.[ICDDiag2] = diag2.[ICD10_CODE]
LEFT JOIN
[StagingDB].[schema].[Diagnosis] AS diag3 ON claim.[ICDDiag3] = diag3.[ICD10_CODE]
-- and so on, up to ....
LEFT JOIN
[StagingDB].[schema].[Diagnosis]AS diag16 ON claim.[ICDDiag16] = diag16.[ICD10_CODE]
-- reported column will be [code_desc]
-- ie:
-- diag1.[code_desc] AS Diagnosis1
-- diag2.[code_desc] AS Diagnosis2
-- diag3.[code_desc] AS Diagnosis3
-- diag4.[code_desc] AS Diagnosis4
-- etc.
I think what you are doing is already correct in given scenario.
Another way can be from programming point of view or you can give try and compare ther performace.
i) Pivot Claim table on those 16 description columns.
ii) Join the Pivoted column with [StagingDB].[schema].[Diagnosis]
Another way can be to put [StagingDB].[schema].[Diagnosis] table in some #temp table
instead of touching large Staging 16 times.
But for data analysis has to be done to decide if there is any way.
You can go for UNPIVOT of the claimTable and then join with Diagnosis table.
TEST SETUP
create table #claimTable(ClaimId INT, Diag1 VARCHAR(10), Diag2 VARCHAR(10))
CREATE table #Diagnosis(code VARCHAR(10), code_Desc VARCHAR(255))
INSERT INTO #ClaimTable
VALUES (1, 'Fever','Cold'), (2, 'Headache','toothache');
INSERT INTO #Diagnosis
VALUEs ('Fever','Fever Desc'), ('cold','cold desc'),('headache','headache desc'),('toothache','toothache desc');
Query to Run
;WITH CTE_Claims AS
(SELECT ClaimId,DiagnosisNumeral, code
FROM #claimTable
UNPIVOT
(
code FOR DiagnosisNumeral in ([Diag1],[Diag2])
) as t
)
SELECT c.ClaimId, c.code, d.code_Desc
FROM CTE_Claims AS c
INNER JOIN #Diagnosis as d
on c.code = d.code
ResultSet
+---------+-----------+----------------+
| ClaimId | code | code_Desc |
+---------+-----------+----------------+
| 1 | Fever | Fever Desc |
| 1 | Cold | cold desc |
| 2 | Headache | headache desc |
| 2 | toothache | toothache desc |
+---------+-----------+----------------+

WHERE inside CASE statement

I have seen lots of posts about putting CASE statements inside WHERE clauses. However, in my case, I want to put a WHERE statement inside a CASE statement, which I don't think can be done.
My situation is that I have a view that is going on many, many databases. In half of them, I need to have a WHERE clause. In the other half, I don't need the WHERE clause. Leaving it in isn't harmful, in that I don't get bad data, but it slows the query down considerably given that it has to read and sort a large table when it is unnecessary.
Status_Table
ID Status
1 Active
2 Inactive
3 Unknown --this row of data will not exist in some DBs
Item_table
Item_ID Status value1 value2
1001 3 ..... .....
1002 1 ..... .....
What I want to do is something like this.
-- big nasty ugly query with various CTEs, selects, and joins
CASE WHEN (SELECT MAX(ID) FROM Status_table) = 3
THEN WHERE Item_Table.Status != 3
ELSE WHERE 1=1
END
Ultimately, I can probably swing this by constructing the query using dynamic SQL, but I was hoping for a more elegant solution.
You're trying to build a conditional WHERE clause, yes? I'd think something like this would work pretty well for what you want to do:
WHERE (EXISTS (SELECT 1 FROM Status_table WHERE ID = 3)
AND Item_Table.Status != 3)
OR
NOT EXISTS (SELECT 1 FROM Status_table WHERE ID = 3)
SQL Fiddle
MS SQL Server 2014 Schema Setup:
CREATE TABLE Status_Table ( ID int, [Status] varchar(30) ) ;
INSERT INTO Status_Table ( ID, [Status] )
VALUES
( 1,'Active' ), (2,'Inactive'), (3,'Unknown')
;
CREATE TABLE Item_table ( Item_ID int, [Status] int, value1 varchar(10), value2 varchar(10) ) ;
/* NOTE: Item_table.[Status] should be a descriptive name, like [StatusID], or something not the same name as a different datatype column in the relation table. */
INSERT INTO Item_Table ( Item_ID, [Status], value1, value2 )
VALUES (1001,3,'Bill','Exclude')
,(1002,1,'Ted','Include')
,(1003,3,'Rufus','Exclude')
,(1004,2,'Jay','Include')
,(1005,5,'Bob','BadRecord')
;
Query 1:
SELECT s1.Item_ID, s1.Status, s1.Value1, s1.Value2
FROM (
SELECT i.Item_ID, i.Status, i.Value1, i.Value2
, RANK() OVER (ORDER BY s.ID DESC) AS rn
FROM Item_Table i
RIGHT OUTER JOIN Status_Table s ON i.[Status] = s.ID
) s1
WHERE s1.rn <> 1
Results:
| Item_ID | Status | Value1 | Value2 |
|---------|--------|--------|---------|
| 1004 | 2 | Jay | Include |
| 1002 | 1 | Ted | Include |
If its performance your after start using DECLARE and SET.
It only needs to execute ONCE!!!
DECLARE #UnkownExists AS INT
SET #UnkownExists = (select count(*) from Status_table where ID = 3)
-- big nasty ugly query with various CTEs, selects, and joins
WHERE (#UnkownExists=1 AND Item_Table.Status != 3) OR #NoUnknown=0
You can try this:
CASE WHEN (SELECT MAX(ID) FROM Status_table) = 3
THEN 3
ELSE (SELECT MAX(ID)+1 FROM Status_table) --Invalid value that will not exist
END <> Item_Table.Status

SQL Select Records ONLY When a Column Value Is In More Than Once

I have a stored procedure in SQL Server, I am trying to select only the records where a column's value is in there more than once, This may seem a bit of an odd request but I can't seem to figure it out, I have tried using HAVING clauses but had no luck..
I want to be able to only select records that have the ACCOUNT in there more than once, So for example:
ACCOUNT | PAYDATE
-------------------
B066 | 15
B066 | OUTSTAND
B027 | OUTSTAND <--- **SHOULD NOT BE IN THE SELECT**
B039 | 09
B039 | OUTSTAND
B052 | 09
B052 | 15
B052 | OUTSTAND
BO27 should NOT show in my select, and the rest of the ACCOUNTS should.
here is my start and end of the Stored Procedure:
Select * from (
*** SELECTS ARE HERE ***
) X where O_STAND <> 0.0000
group by X.ACCOUNT, X.ACCT_NAME , X.DAYS_CR, X.PAYDATE, X.O_STAND
order by X.ACCOUNT
I have been struggling with this for a while, any help or advice would be appreciated. Thank you in advance.
you could replace the first string with
Select *, COUNT(*) OVER (PARTITION BY ACCOUNT) cnt FROM (
and then wrap your query as subquery once more
SELECT cols FROM ( query ) q WHERE cnt>1
Yes, the having clause is for solving exactly this kind of tasks. Basically, it's like where, but allows to filter not only by column values, but also by aggregate functions' results:
declare #t table (
Id int identity(1,1) primary key,
AccountId varchar(20)
);
insert into #t (AccountId)
values
('B001'),
('B002'),
('B015'),
('B015'),
('B002');
-- Get all rows for which AccountId value is encountered more than once in the table
select *
from #t t
where exists (
select 0
from #t h
where h.AccountId = t.AccountId
group by h.AccountId
having count(h.AccountId) > 1
);

Join tables by column names, convert string to column name

I have a table which store 1 row per 1 survey.
Each survey got about 70 questions, each column present 1 question
SurveyID Q1, Q2 Q3 .....
1 Yes Good Bad ......
I want to pivot this so it reads
SurveyID Question Answer
1 Q1 Yes
1 Q2 Good
1 Q3 Bad
... ... .....
I use {cross apply} to acheive this
SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
select 1 as QuestionNumber, 'Q1' as Question , t.Q1 As Answer union all
select 2 as QuestionNumber, 'Q2' as Question , t.Q2 As Answer union all
select 3 as QuestionNumber, 'Q3' as Question , t.Q3 As Answer) x
This works but I dont want to do this 70 times so I have this select statement
select ORDINAL_POSITION
, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = mytable
This gives me the list of column and position of column in the table.
So I hope I can somehow join 2nd statement with the 1st statement where by column name. However I am comparing content within a column and a column header here. Is it doable? Is there other way of achieving this?
Hope you can guide me please?
Thank you
Instead of Cross Apply you should use UNPIVOT for this query....
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Test_Table(SurveyID INT, Q1 VARCHAR(10)
, Q2 VARCHAR(10), Q3 VARCHAR(10), Q4 VARCHAR(10))
INSERT INTO Test_Table VALUES
(1 , 'Yes', 'Good' , 'Bad', 'Bad')
,(2 , 'Bad', 'Bad' , 'Yes' , 'Good')
Query 1:
SELECT SurveyID
,Questions
,Answers
FROM Test_Table t
UNPIVOT ( Answers FOR Questions IN (Q1,Q2,Q3,Q4))up
Results:
| SurveyID | Questions | Answers |
|----------|-----------|---------|
| 1 | Q1 | Yes |
| 1 | Q2 | Good |
| 1 | Q3 | Bad |
| 1 | Q4 | Bad |
| 2 | Q1 | Bad |
| 2 | Q2 | Bad |
| 2 | Q3 | Yes |
| 2 | Q4 | Good |
If you need to perform this kind of operation to lots of similar tables that have differing numbers of columns, an UNPIVOT approach alone can be tiresome because you have to manually change the list of columns (Q1,Q2,Q3,etc) each time.
The CROSS APPLY based query in the question also suffers from similar drawbacks.
The solution to this, as you've guessed, involves using meta-information maintained by the server to tell you the list of columns you need to operate on. However, rather than requiring some kind of join as you suspect, what is needed is Dynamic SQL, that is, a SQL query that creates another SQL query on-the-fly.
This is done essentially by concatenating string (varchar) information in the SELECT part of the query, including values from columns which are available in your FROM (and join) clauses.
With Dynamic SQL (DSQL) approaches, you often use system metatables as your starting point. INFORMATION_SCHEMA exists in some SQL Server versions, but you're better off using the Object Catalog Views for this.
A prototype DSQL solution to generate the code for your CROSS APPLY approach would look something like this:
-- Create a variable to hold the created SQL code
-- First, add the static code at the start:
declare #SQL varchar(max) =
' SELECT t.[SurveyID]
, x.question
, x.Answer
FROM tbl t
CROSS APPLY
(
'
-- This syntax will add to the variable for every row in the query results; it's a little like looping over all the rows.
select #SQL +=
'select ' + cast(C.column_id as varchar)
+ ' as QuestionNumber, ''' + C.name
+ ''' as Question , t.' + C.name
+ ' As Answer union all
'
from sys.columns C
inner join sys.tables T on C.object_id=T.object_id
where T.name = 'MySurveyTable'
-- Remove final "union all", add closing bracket and alias
set #SQL = left(#SQL,len(#SQL)-10) + ') x'
print #SQL
-- To also execute (run) the dynamically-generated SQL
-- and get your desired row-based output all at the same time,
-- use the EXECUTE keyword (EXEC for short)
exec #SQL
A similar approach could be used to dynamically write SQL for the UNPIVOT approach.

Resources