SQL Query-Transform the below table to required format - sql

Need help on below questions.Please provide some pointers/suggestions.
Transform the below table to required format shown below:
I created the table at below link:
https://rextester.com/EEFTL51608

Note that i have changed the value to integer. If the data type in your original table is not numeric, you will required another step to convert to numeric so that it is able to sum up in the final result
Create table ProdTable
(
Product nvarchar(50),
[2012] int,
[2013] int ,
[2014] int ,
[2015] int ,
)
GO
Insert into ProdTable values ('Cars','100','125','200','175');
Insert into ProdTable values ('shirts','125','75','100','155');
Insert into ProdTable values ('Cars','75','115','100','255');
Insert into ProdTable values ('Pens','140','100','105','185');
Insert into ProdTable values ('Flowers','155','120','145','165');
select * from ProdTable
select *
from ProdTable
unpivot
(
value
for year in ([2012], [2013], [2014], [2015])
) u
pivot
(
sum(value)
for Product in ([Cars], [shirts], [Pens], [Flowers])
) p

You need unpivot & pivot so i would do :
select year, max(case when t.product = 'Cars' then val end) as Cars,
max(case when t.product = 'shirts' then val end) as shirts,
max(case when t.product = 'Pens' then val end) as Pens,
max(case when t.product = 'Flowers' then val end) as Flowers
from table t cross apply
( values ('2012', [2012]), ('2013', [2013]), ('2014', [2014]), ('2015', [2015])
) tt(year, val)
group by year;

Related

Cross apply boolean values in SQL

I had the table below which I need to create a Category column will store the boolean values as a category.
I would like to capture the Categories as a single column and I don't mind having duplicate rows in the view. I would like the first row to return Contract and the second the other value selected, for the same Reference ID.
I achieved his using the query below:
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation)
) tt(category, flag)
where flag = 1;
How can I capture an additional Category None where all instances of Contract, Tender, Waiver and Quotation are 0?
None can go right into your VALUES clause. You case use a case expression for the logic. Alternatively, you can use a trick with sign():
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation),
('None', 1 - sign(t.Contracts + t.Tender + t.Waiver + t.Quotation))
) tt(category, flag)
where flag = 1;
I am guessing that you don't have duplicates in your original table, so you should dispense with SELECT DISTINCT.
Maybe something like this:
select distinct t.*, tt.category
from t cross apply
( values ('Contracts', t.Contracts),
('Tender', t.Tender),
('Waiver', t.Waiver),
('Quotation', t.Quotation),
('None', -1)
) tt(category, flag)
where flag = 1 or
(Contracts = 0 and Tender = 0 and Waiver = 0 and Quotation = 0 and flag = -1);
Here's my sample fiddle (guessing you have bit fields, but it works with int fields too): http://sqlfiddle.com/#!18/9f8e7/1
I hope following SQL query can also help you
create table myTable (
ReferenceId int,
Contract int,
Tender int,
Waiver int,
Quotation int
)
insert into myTable select 1212,1,0,1,0
insert into myTable select 1213,1,1,0,0
insert into myTable select 1214,0,1,0,0
insert into myTable select 1215,1,0,1,0
insert into myTable select 1216,0,0,0,1
insert into myTable select 1217,0,0,1,0
insert into myTable select 1218,0,0,0,0
;with cte as (
select
*,
ISNULL(NULLIF(
CONCAT_WS(',',
case when Contract = 1 then 'Contract' end,
case when Tender = 1 then 'Tender' end,
case when Waiver = 1 then 'Waiver' end,
case when Quotation = 1 then 'Quotation' end
)
,''),'None')
as Category
from myTable
)
select
ReferenceId, Contract, Tender, Waiver, Quotation, c.val as Category
from cte
cross apply split(Category,',') as c
Here you need a user-defined SQL function SPLIT where the source codes can be found
The output as follows
declare #t table
(
ReferenceId int,
Contracts bit,
Tender bit,
Waiver bit,
Quotation bit
)
insert into #t(ReferenceId, Contracts, Tender, Waiver, Quotation)
values
(123, 0, 1, 0, 0),
(234, 0, 0, 0, 1),
(345, 0, 0, 0, 0);
select *
from
(
select ReferenceId,
Contracts, nullif(Tender, 0) as Tender, nullif(Waiver, 0) as Waiver, nullif(Quotation, 0) as Quotation,
case when cast(Contracts as int)+Tender+Waiver+Quotation > 0 then cast(null as bit) else cast(0 as bit) end as [None]
from #t
)as t
unpivot
(
Flag for Category in (Contracts, Tender, Waiver, Quotation, [None])
) as unpv;
This is ugly, but I don't think it's a bad idea
select *, 'contract' as category
from t where contract=1 union
select *, 'waiver'
from t where waiver=1 union
select *, 'tender'
from t where tender=1 union
select *, 'quotation'
from t where quotation=1 union
select *, 'none'
from t where (contract+waiver+tender+quotation)=0
order by referenceid;

How to pivot values from rows to column based on value from related column

I am trying to pivot a set of data based on 3 value, so that each row represents all the profile URLs related to each ID, with each column relating to the profile code
This question is very similar to what I am trying to achieve, however it is not grouping the columns that are being pivoted based on another value: Pivot values on column based on grouped columns in SQL
So given the following example table:
Id ProfileCode ProfileURL
-------------------------------------------------------
7ADC7368 IA http://www.domainIA.com/profile1
5C627D6F IA http://www.domainIA.com/profile2
5C627D6F AG http://www.domainAG.com/profile1
5C627D6F AF http://www.domainAF.com/profile1
664B4AE9 IA http://www.domainIA.com/profile3
664B4AE9 AF http://www.domainAF.com/profile2
I am hoping to transform it into the following table:
Id IA AG AF
-------------------------------------------------------------------------------------------------------------
7ADC7368 http://www.domainIA.com/profile1 null null
5C627D6F http://www.domainIA.com/profile2 http://www.domainAG.com/profile1 http://www.domainAF.com/profile1
664B4AE9 http://www.domainIA.com/profile3 null http://www.domainAF.com/profile2
This is the code I have been trying to work, but I cannot find a way to relate the pivot to the association between the profile URL and its associated profile code.
declare #tmp TABLE (Id NVARCHAR(15), ProfileCode NVARCHAR(2), ProfileURL NVARCHAR(50))
insert into #tmp (Id, ProfileCode, ProfileURL)
values ('7ADC7368', 'IA', 'http://www.domainIA.com/profile1'),
('5C627D6F', 'IA', 'http://www.domainIA.com/profile2'),
('5C627D6F', 'AG', 'http://www.domainAG.com/profile1'),
('5C627D6F', 'AF', 'http://www.domainAF.com/profile1'),
('664B4AE9', 'IA', 'http://www.domainIA.com/profile3'),
('664B4AE9', 'AF', 'http://www.domainAF.com/profile2')
select
pvt.id,
CASE
WHEN ProfileCode = 'IA' THEN ProfileURL
END AS 'IA',
CASE
WHEN ProfileCode = 'AF' THEN ProfileURL
END AS 'AF',
CASE
WHEN ProfileCode = 'AG' THEN ProfileURL
END AS 'AG'
from (
select
Id, ProfileCode, ProfileURL
,ROW_NUMBER() over(partition by ProfileCode order by ProfileURL) as RowNum
from
#tmp
) a
pivot (MAX(ProfileCode) for RowNum in ('IA', 'AF', 'AG') as pvt
I greatly would appreciate any help or pointers with what I am trying to achieve.
Just use conditional aggregation:
SELECT id,
MAX(CASE WHEN ProfileCode = 'IA' THEN ProfileURL END) AS IA,
MAX(CASE WHEN ProfileCode = 'AF' THEN ProfileURL END) AS AF,
MAX(CASE WHEN ProfileCode = 'AG' THEN ProfileURL END) AS AG
FROM #tmp t
GROUP BY id;
You only need ROW_NUMBER() if you have multiple of the same code for a given id and you want the results on separate rows. Your sample data and current logic suggest that this is not the case.

T-SQL - Copying & Transposing Data

I'm trying to copy data from one table to another, while transposing it and combining it into appropriate rows, with different columns in the second table.
First time posting. Yes this may seem simple to everyone here. I have tried for a couple hours to solve this. I do not have much support internally and have learned a great deal on this forum and managed to get so much accomplished with your other help examples. I appreciate any help with this.
Table 1 has the data in this format.
Type Date Value
--------------------
First 2019 1
First 2020 2
Second 2019 3
Second 2020 4
Table 2 already has the Date rows populated and columns created. It is waiting for the Values from Table 1 to be placed in the appropriate column/row.
Date First Second
------------------
2019 1 3
2020 2 4
For an update, I might use two joins:
update t2
set first = tf.value,
second = ts.value
from table2 t2 left join
table1 tf
on t2.date = tf.date and tf.type = 'First' left join
table1 ts
on t2.date = ts.date and ts.type = 'Second'
where tf.date is not null or ts.date is not null;
use conditional aggregation
select date,max(case when type='First' then value end) as First,
max(case when type='Second' then value end) as Second from t
group by date
You can do conditional aggregation :
select date,
max(case when type = 'first' then value end) as first,
max(case when type = 'Second' then value end) as Second
from table t
group by date;
After that you can use cte :
with cte as (
select date,
max(case when type = 'first' then value end) as first,
max(case when type = 'Second' then value end) as Second
from table t
group by date
)
update t2
set t2.First = t1.First,
t2.Second = t1.Second
from table2 t2 inner join
cte t1
on t1.date = t2.date;
Seems like you're after a PIVOT
DECLARE #Table1 TABLE
(
[Type] NVARCHAR(100)
, [Date] INT
, [Value] INT
);
DECLARE #Table2 TABLE(
[Date] int
,[First] int
,[Second] int
)
INSERT INTO #Table1 (
[Type]
, [Date]
, [Value]
)
VALUES ( 'First', 2019, 1 )
, ( 'First', 2020, 2 )
, ( 'Second', 2019, 3 )
, ( 'Second', 2020, 4 );
INSERT INTO #Table2 (
[Date]
)
VALUES (2019),(2020)
--Show us what's in the tables
SELECT * FROM #Table1
SELECT * FROM #Table2
--How to pivot the data from Table 1
SELECT * FROM #Table1
PIVOT (
MAX([Value]) --Pivot on this Column
FOR [Type] IN ( [First], [Second] ) --Make column where [Value] is in one of this
) AS [pvt] --Table alias
--which gives
--Date First Second
------------- ----------- -----------
--2019 1 3
--2020 2 4
--Using that we can update #Table2
UPDATE [tbl2]
SET [tbl2].[First] = pvt.[First]
,[tbl2].[Second] = pvt.[Second]
FROM #Table1 tbl1
PIVOT (
MAX([Value]) --Pivot on this Column
FOR [Type] IN ( [First], [Second] ) --Make column where [Value] is in one of this
) AS [pvt] --Table alias
INNER JOIN #Table2 tbl2 ON [tbl2].[Date] = [pvt].[Date]
--Results from #Table 2 after updated
SELECT * FROM #Table2
--which gives
--Date First Second
------------- ----------- -----------
--2019 1 3
--2020 2 4

Pivot outputs two values

create table #Contact(
LoanNumber int,
ContactType varchar(10),
CompanyName varchar(10),
CompanyPhone varchar(10),
CONSTRAINT PK PRIMARY KEY (LoanNumber,ContactType)
)
Insert into #Contact
values (1,'Appriaser','Yige King','11' ),
(1,'AssetOwner','gqqnbig','22' )
This is my table. ContactTypes are only Appriaser and AssetOwner.
Can I get a table like
LoanNumber AppraiserCompanyName AppraiserCompanyPhone AssertOwnerCompanyName AssertOwnerCompanyPhone
----------------------------------------------------------------------------------------------------
6103339 YigeKing 11 gqqnbig 22
I managed to write this
select LoanNumber,
CompanyNamePT.Appriaser as AppriaserCompanyName, CompanyNamePT.AssetOwner as AssetOwnerCompanyName
--CompanyPhonePT.Appriaser as AppriaserCompanyPhone, CompanyPhonePT.AssetOwner as AssetOwnerCompanyPhone
from (
select #contact.LoanNumber, #contact.ContactType, #contact.CompanyName
from #contact
) as c
pivot ( max(c.CompanyName) for c.ContactType in (Appriaser,AssetOwner)) as CompanyNamePT
--pivot ( max(c.CompanyPhone) for c.ContactType in ([Appriaser],[AssetOwner])) as CompanyPhonePT
It outputs company names, but if I uncomment the two lines to get phone number, it throws syntax error.
How can I make it work? Ideally I want to use pivot because I'm learnig it.
For the desired PIVOT
Select *
From (
Select C.LoanNumber
,B.*
From #Contact C
Cross Apply ( values (IIF(ContactType='Appriaser' ,'AppraiserCompanyName' , 'AssetOwnerCompanyName') ,C.CompanyName)
,(IIF(ContactType='Appriaser' , 'AppraiserCompanyPhone', 'AssetOwnerCompanyPhone'),C.CompanyPhone)
) B (Item,Value)
) A
pivot ( max(A.Value) for A.Item in ([AppraiserCompanyName],[AppraiserCompanyPhone],[AssetOwnerCompanyName],[AssetOwnerCompanyPhone]) ) P
But a Conditional Aggregation would do as well
Select C.LoanNumber
,AppraiserCompanyName = max(case when ContactType='Appriaser' then C.CompanyName end)
,AppraiserCompanyPhone = max(case when ContactType='Appriaser' then C.CompanyPhone end)
,AssetOwnerCompanyName = max(case when ContactType='AssetOwner' then C.CompanyName end)
,AssetOwnerCompanyPhone = max(case when ContactType='AssetOwner' then C.CompanyPhone end)
From #Contact C
Group By C.LoanNumber
Both Would Return
If it Helps with the Visualization, the sub-query with the Cross Apply Generates

Calculating using Variables in MYSQL query

hope you can help, this is driving me up the wall
I need to calculate the percentage of times a question has been failed, but this needs to be narrowed down by the geographical area, and product these questions are being asked against.
I have :
$CA002 = "( SELECT ROUND(100 * (SELECT count(CA002Result) from Data_Table where (CA002Result='Fail'))/count(CA002Result),2) from Data_Table) AS 'CA002 %'";
Which 'works' but just calculates against the whole set of records as an 'overall'
I'm trying :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result) from Data_Table where (CA001Result='Fail' AND Area ='$Area'))/count(CA001Result) from Data_Table WHERE (Area='$Area'),2) AS 'CA001 %'";
And Also :
$CA001 = "( SELECT ROUND(100 * (SELECT count(CA001Result ) from Data_Table where (CA001Result='Fail' AND Product='$product' AND Area='$Area'))
/ count(CA001Result WHERE Product = '$product' AND Area='$Area'),2) from Data_Table) AS 'CA001 %'";
and am just getting errors no matter what I try, I just can't seem to work out what I need to put where.
Any great GREATLY apprteciated, thankyou.
Try this
//Filter by Area
create table t( id int, answer varchar(10),Area varchar(10));
insert into t select 1 , 'pass' , 'Area1';
insert into t select 2 , 'pass' , 'Area1';
insert into t select 3 , 'fail' , 'Area1';
insert into t select 4 , 'fail' , 'Area1';
insert into t select 5 , 'fail' , 'Area1';
insert into t select 6 , 'fail' , 'Area2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1'
GROUP BY Area
)x
INNER JOIN
( SELECT Area,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1'
GROUP BY Area
)y ON x.Area =y.Area
//Result
Fail_percent
-------------
60
//Filter by Area,Product
create table t( id int, answer varchar(10),Area varchar(10),Product varchar(10));
insert into t select 1 , 'pass' , 'Area1' ,'Product1';
insert into t select 2 , 'fail' , 'Area1' ,'Product1';
insert into t select 3 , 'fail' , 'Area1' ,'Product1';
insert into t select 4 , 'fail' , 'Area1' ,'Product1';
insert into t select 5 , 'fail' , 'Area1' ,'Product2';
insert into t select 6 , 'fail' , 'Area2' ,'Product2';
SELECT
(x.TotalFailedAnswerRecord * 100) /y.TotalRecord AS Fail_percent
FROM
( SELECT Area,Product,TotalFailedAnswerRecord = COUNT(answer)
FROM t
WHERE answer='fail' AND Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)x
INNER JOIN
( SELECT Area,Product,TotalRecord = COUNT(answer)
FROM t
WHERE Area = 'Area1' AND Product = 'Product1'
GROUP BY Area,Product
)y ON x.Area =y.Area AND x.Product = y.Product
//Result
Fail_percent
-------------
75
Hope this helps