I am using SQL Server 2012, self-taught so sorry for any errors/mistakes.
I have a table that I had pivot and the resulting table has null values like so:
Pepsi Coke Gatorade
--------------------------
Vanilla NULL NULL
Cherry NULL NULL
NULL Vanilla NULL
NULL Cherry NULL
NULL NULL Lime
NULL NULL Fruit Punch
NULL NULL Grape
My question is if there is a way to rearrange the table so that the rows that are not null show up at the top of their respective columns in such a way so that if another user was to add a different type of drink, such as water, that the query would be to automatically sort the newly added column. If this cannot be accomplished then an alternative suggestion would be appreciated.
An example of the desired result would be like so:
Pepsi Coke Gatorade
------------------------------
Vanilla Vanilla Lime
Cherry Cherry Fruit Punch
NULL NULL Grape
I have tried doing a series of outer joins from the FROM clause however, I cannot figure out a way to generate the results without explicitly calling the columns and/or table names.
select distinct t1.Pepsi, t2.Coke from
(select
#test.Pepsi as Pepsi,
ROW_NUMBER() over (order by Pepsi) r
from #test
where Pepsi is not null) as t1
full outer join
(select
#test.Coke as Coke,
ROW_NUMBER() over (order by Coke) r
from #test
where Coke is not null) as t2
on t1.r=t2.r
The original table looks like so:
Drink Type Price Location etc
Coke Vanilla
Coke Cherry
Gatorade Lime
Gatorade Grape
.
.
.
Pepsi Cherry
Any advice or help is greatly appreciated.
DECLARE #t TABLE ([Drink] varchar(max), [Type] varchar(max), [Price] money )
INSERT #t
([Drink],[Type])
VALUES
('Coke','Vanilla'),
('Coke','Cherry'),
('Gatorade','Lime'),
('Gatorade','Grape'),
('Gatorade','Fruit Punch'),
('Pepsi','Vanilla'),
('Pepsi','Cherry')
;WITH t AS (
SELECT
[Drink],[Type],
ROW_NUMBER() OVER(PARTITION BY [Drink] ORDER BY [Type] DESC) rn
FROM #t
)
SELECT [Pepsi],[Coke],[Gatorade]
FROM t
PIVOT(MAX([Type]) FOR [Drink] IN ([Pepsi],[Coke],[Gatorade])) p
Related
I want to combine multiple product entries into 1 and also sum their price. Currently, the database looks like this :
Name Product Price
Zack Vanilla Twist 1
Jane Lolipop 0.5
Zack Lolipop 0.5
Zack Candymint 0.5
Jane ChocoLoco LM 1.5
I want to change the look of this into something like this:
Name Product sum(Price)
Zack Vanilla Twist, Lolipop, Candymint 2
Jane Lolipop, ChocoLoco LM 2
How to do this using Impala SQL?
This query works for MySQL, this might help you.
select Name, group_concat(`product` separator ', ') Product, sum(Price)
from tempt
group by Name
order by Name desc
dbfiddle here
declare #temp table (Name varchar(50), product varchar(50), Price decimal(3,1))
insert into #temp values ('Zack','Vanilla Twist',1)
insert into #temp values ('Jane','Lolipop',0.5)
insert into #temp values ('Zack','Lolipop',0.5)
insert into #temp values ('Zack','Candymint',0.5)
insert into #temp values ('Jane','ChocoLoco LM',1.5)
-- No cursor, Whil loop, or User defined function:
SELECT
Name,
STUFF((
SELECT ', ' + product
FROM #temp
WHERE (name = Results.name)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS Product
,sum(Price) as [Sum(Price)]
FROM #temp Results
GROUP BY name
Output:
Name Product Sum(Price)
Jane Lolipop, ChocoLoco LM 2
Zack Vanilla Twist, Lolipop, Candymint 2
I'm trying to take an ugly SQL output and use SSRS to make it suitable for export to a mail house.
What would be the right approach to group data from this:
order_no
type
name
item
price
1
header
sally
NULL
NULL
1
data
NULL
book
12.50
1
data
NULL
dvd
39.00
2
header
bob
NULL
NULL
2
data
NULL
shirt
50.00
2
data
NULL
shorts
65.00
Into this?
order_no
type
name
item_1
price_1
item_2
price_2
1
header
sally
book
12.50
dvd
39.00
2
header
bob
shirt
50.00
shorts
65.00
Should this be a Matrix? I'm having trouble getting making progress.
There may be a much cleaner way of doing this but this is the approach I took...
First I replicated your sample data
DECLARE #t TABLE(order_no int, [type] varchar(20), [name] varchar(20), [item] varchar(20), price decimal (10,2))
INSERT INTO #t VALUES
(1,'header', 'sally' , NULL, NULL ),
(1,'data', NULL , 'book', 12.50),
(1,'data', NULL , 'dvd', 39.00),
(2,'header', 'bob' , NULL, NULL ),
(2,'data', NULL , 'shirt', 50.00),
(2,'data', NULL , 'shorts', 65.00)
;
WITH o (order_no, [type], [name], [item], [price], [ItemNumber]) AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY order_no ORDER BY item) AS ItemNumber FROM #t WHERE [type] != 'header'
)
SELECT
h.order_no, h.[type], h.name
, d.ItemNumber, d.ItemCaption, d.ItemValue
FROM (SELECT DISTINCT order_no, [Type], [name] FROM #t WHERE [type] = 'header') h
JOIN
(
SELECT order_no, ItemNumber, 'Item_' + CAST(ItemNumber as varchar(10)) as ItemCaption, Item as ItemValue from o
UNION
SELECT order_no, ItemNumber, 'Price_' + CAST(ItemNumber as varchar(10)) as ItemCaption, CAST(Price as varchar(20)) as ItemValue from o
) d ON h.order_no = d.order_no
I created a CTE just to clean up the query a little and included an row_number for each item, we'll use this to created column captions which we can use in the matrix.
This gives us the following output
We now have everything in place for a simple matrix.
Note: As we had to convert everything to strings, the prices are no longer numbers so bear this in mind if you plan on doing anything else with the data later - they would have to be converted back
So, create a new report, add a new dataset and use the above query as the dataset query.
Add a matrix control, drag order_no to the row placeholder, ItemCaption to the column placeholder and ItemValue to the data placeholder.
Next, right-click the order_no column and choose "insert column - inside group right", the set new column value to your type field. Repeat for the header field.
Your design will look like this.
Finally In the column group sort properties, sort by ItemNumber then ItemCaption
The final report looks like this...
I've looked at some answers but none of them seem to be applicable to me.
Basically I have this result set:
RowNo | Id | OrderNo |
1 101 1
2 101 10
I just want to convert this to
| Id | OrderNo_0 | OrderNo_1 |
101 1 10
I know I should probably use PIVOT. But the syntax is just not clear to me.
The order numbers are always two. To make things clearer
And if you want to use PIVOT then the following works with the data provided:
declare #Orders table (RowNo int, Id int, OrderNo int)
insert into #Orders (RowNo, Id, OrderNo)
select 1, 101, 1 union all select 2, 101, 10
select Id, [1] OrderNo_0, [2] OrderNo_1
from (
select RowNo, Id, OrderNo
from #Orders
) SourceTable
pivot (
sum(OrderNo)
for RowNo in ([1],[2])
) as PivotTable
Reference: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
Note: To build each row in the result set the pivot function is grouping by the columns not begin pivoted. Therefore you need an aggregate function on the column that is being pivoted. You won't notice it in this instance because you have unique rows to start with - but if you had multiple rows with the RowNo and Id you would then find the aggregation comes into play.
As you say there are only ever two order numbers per ID, you could join the results set to itself on the ID column. For the purposes of the example below, I'm assuming your results set is merely selecting from a single Orders table, but it should be easy enough to replace this with your existing query.
SELECT o1.ID, o1.OrderNo AS [OrderNo_0], o2.OrderNo AS [OrderNo_1]
FROM Orders AS o1
INNER JOIN Orders AS o2
ON (o1.ID = o2.ID AND o1.OrderNo <> o2.OrderNo)
From your sample data, simplest you can try to use min and MAX function.
SELECT Id,min(OrderNo) OrderNo_0,MAX(OrderNo) OrderNo_1
FROM T
GROUP BY Id
This question already has answers here:
Turning a Comma Separated string into individual rows
(16 answers)
Closed 4 years ago.
I have data that currently looks like this (pipe indicates separate columns):
ID | Sex | Purchase | Type
1 | M | Apple, Apple | Food, Food
2 | F | Pear, Barbie, Soap | Food, Toys, Cleaning
As you can see, the Purchase and Type columns feature multiple values that are comma delimited (some of the cells in these columns actually have up to 50+ values recorded within). I want the data to look like this:
ID | Sex | Purchase | Type
1 | M | Apple | Food
1 | M | Apple | Food
2 | F | Pear | Food
2 | F | Barbie | Toys
2 | F | Soap | Cleaning
Any ideas on how would I be able to do this with SQL? Thanks for your help everyone.
Edit: Just to show that this is different to some of the other questions. The key here is that data for each unique row is contained across two separate columns i.e. the second word in "Purchase" should be linked with the second word in "Type" for ID #1. The other questions I've seen was where the multiple values had been contained in just one column.
Basically you will required a delimited spliter function. There are many around. Here i am using DelimitedSplit8K from Jeff Moden http://www.sqlservercentral.com/articles/Tally+Table/72993/
-- create the sample table
create table #sample
(
ID int,
Sex char,
Purchase varchar(20),
Type varchar(20)
)
-- insert the sample data
insert into #sample (ID, Sex, Purchase, Type) select 1, 'M', 'Apple,Apple', 'Food,Food'
insert into #sample (ID, Sex, Purchase, Type) select 2, 'M', 'Pear,Barbie,Soap', 'Food,Toys,Cleaning'
select s.ID, s.Sex, Purchase = p.Item, Type = t.Item
from #sample s
cross apply DelimitedSplit8K(Purchase, ',') p
cross apply DelimitedSplit8K(Type, ',') t
where p.ItemNumber = t.ItemNumber
drop table #sample
EDIT: The original question as posted had the data as strings, with pipe characters as column delimiters and commas within the columns. The below solution works for that.
The question has since been edited to show that the input data is actually in columns, not as a single string.
I've left the solution here as an interesting version of the original question.
This is an interesting problem. I have a solution that works for a single row of your data. I dont know from the question if you are going to process it row by row, but I assume you will.
If so, this will work. I suspect there might be a better way using xml or without the temp tables, but in any case this is one solution.
declare #row varchar(1000); set #row='2 | F | Pear, Barbie, Soap | Food, Toys, Cleaning'
declare #v table(i int identity, val varchar(1000), subval varchar(100))
insert #v select value as val, subval from STRING_SPLIT(#row,'|')
cross apply (select value as subval from STRING_SPLIT(value,',') s) subval
declare #v2 table(col_num int, subval varchar(100), correlation int)
insert #v2
select col_num, subval,
DENSE_RANK() over (partition by v.val order by i) as correlation
from #v v
join (
select val, row_number()over (order by fst) as Col_Num
from (select val, min(i) as fst from #v group by val) colnum
) c on c.val=v.val
order by i
select col1.subval as ID, col2.subval as Sex, col3.subval as Purchase, col4.subval as Type
from #v2 col1
join #v2 col2 on col2.col_num=2
join #v2 col3 on col3.col_num=3
join #v2 col4 on col4.col_num=4 and col4.correlation=col3.correlation
where col1.col_num=1
Result is:
ID Sex Purchase Type
2 F Pear Food
2 F Barbie Toys
2 F Soap Cleaning
sorry if this has already been posted but I've been through umpteen posts on pivoting the past day and still havn't been able to get the result i want.
Background:
In short, I am developing a set of tables that will store a questionnaire dynamically.
I wont go into detail of it probably isnt relative.
I basically want to query the table that stores the user input for a set question.
These questions branch off each other allowing me to show columns and rows per question etc.
Anyway this query:
SELECT qr.*, Question
FROM QuestionRecord qr
INNER JOIN
QuestionRecord P
ON P.ID = qr.ParentQuestionRecordId
JOIN Questions q ON q.ID = qr.QuestionID
Produces this result set :
ID FormRecordId QuestionId ParentQuestionRecordId Value Question
---------------------------------------------------------------------------------------
2 1 31 1 Consultancy Eligible project costs
3 1 32 2 NULL Date
4 1 33 2 25000 Cash Costs £
5 1 34 2 NULL In Kind Costs £
6 1 35 2 25000 Total Costs
7 1 31 1 Orchard day x2 Eligible project costs
8 1 32 7 NULL Date
9 1 33 7 15000 Cash Costs £
10 1 34 7 NULL In Kind Costs £
11 1 35 7 15000 Total Costs
I basically want to Pivot(I think) these rows to look like so:
Eligible project costs Date Cash Costs £ In Kind Costs Total Costs
--------------------------------------------------------------------------------
Consultancy NULL 25000 NULL 25000
Orchard day x2 NULL 15000 NULL 15000
I have tried:
SELECT [Eligible project costs],[Date],[Cash Costs £],[In Kind Costs £],[Total Costs]
FROM
(
SELECT qr.*, Question
FROM QuestionRecord qr
INNER JOIN
QuestionRecord P
ON P.ID = qr.ParentQuestionRecordId
JOIN Questions q ON q.ID = qr.QuestionID
)pvt
PIVOT
(
MIN(Value)
FOR Question IN
([Eligible project costs],[Date],[Cash Costs £],[In Kind Costs £],[Total Costs])
)pivotTable
but this returns each column on a seperate row:
Eligible project costs Date Cash Costs £ In Kind Costs Total Costs
--------------------------------------------------------------------------------
Consultancy NULL NULL NULL NULL
NULL NULL NULL NULL NULL
NULL NULL 25000 NULL NULL
NULL NULL NULL NULL NULL
NULL NULL NULL NULL 25000
So that's as close as i have managed to get with it, i was wondering if you guys/girls could help me out :)
Thanks!
Try the following changes to your script (strikethrough = deleted, bold = added):
SELECT [Eligible project costs],[Date],[Cash Costs £],[In Kind Costs £],[Total Costs]
FROM
(
SELECT qr.*,
grp = ROW_NUMBER() OVER (PARTITION BY qr.QuestionId ORDER BY qr.ID),
Value,
Question
FROM QuestionRecord qr
INNER JOIN
QuestionRecord P
ON P.ID = qr.ParentQuestionRecordId
JOIN Questions q ON q.ID = qr.QuestionID
)pvt
PIVOT
(
MIN(Value)
FOR Question IN
([Eligible project costs],[Date],[Cash Costs £],[In Kind Costs £],[Total Costs])
)pivotTable
I think it must give your the result you are after.
Change SELECT qr.*, Question to SELECT Value, Question. PIVOT groups by the remaining columns.
what you need, like andriy kinda pointed out, is something to make each record unique depending on how you want them grouped. now, if this is a survey system i'm going to guess that you've got some sort of id to identify who the record belongs to. the reason why it's returning on seperate rows is that you have unique records for each row based on those ids, what you need is to add the respondent id to your derived table and get rid of your other id's.
see my example:
declare #table table (ID int identity(1,1), QuestionID int, value varchar(50), Respondent int)
declare #questions table (QID int, name varchar(50))
insert into #questions values (31,'Eligible project costs')
insert into #questions values (32,'Date')
insert into #questions values (33,'Cash Costs')
insert into #questions values (34,'In Kind Costs')
insert into #questions values (35,'Total Costs')
insert into #table values (31,'Consultancy',1)
insert into #table values (32,null,1)
insert into #table values (33,25000,1)
insert into #table values (34,null,1)
insert into #table values (35,25000,1)
insert into #table values (31,'Orchard day x2',2)
insert into #table values (32,null,2)
insert into #table values (33,15000,2)
insert into #table values (34,null,2)
insert into #table values (35,15000,2)
select
[Eligible project costs],[Date],[Cash Costs],[In Kind Costs],[Total Costs]
from
(
select
Respondent,
q.name,
t.Value
from #table t
inner join #questions q
on t.QuestionID=QID
) a
pivot
(
min(Value)
for name in ([Eligible project costs],[Date],[Cash Costs],[In Kind Costs],[Total Costs])
) p