So I have a table that looks like this:
list
value
date
cars
10000
2023-01-28
trucks
20000
2022-12-25
vans
55
2023-01-05
trailers
560
2023-11-11
But I want to pivot it so the list value becomes the column and the values becomes the current value column, like this:
date
cars
trucks
vans
trailers
2023-01-28
10000
NA
NA
NA
2022-12-25
NA
20000
NA
NA
2023-01-05
NA
NA
55
NA
2023-11-11
NA
NA
NA
560
What's the best way to do this? I've tried this:
SELECT * FROM
(select * from `table`)
pivot(sum(list) for list in list)
But this didn't work. Thoughts?
Try going with the CASE expressions:
SELECT date,
MAX(CASE WHEN list = 'cars' THEN value END) AS cars,
MAX(CASE WHEN list = 'trucks' THEN value END) AS trucks,
MAX(CASE WHEN list = 'vans' THEN value END) AS vans
FROM <your_table>
GROUP BY date
Use below simple approach
select * from your_table
pivot (any_value(value) for list in ('cars', 'trucks', 'vans', 'trailers'))
if applied to sample data in your question - output is
you can build that query dynamically (so you will not need to explicitly specify values) and use EXECUTE IMMEDIATE to run it - there are plenty examples of such technique here on SO!
Related
I have a table containing numbers of people in each area, by age.
There is a column for each age, as shown in this table (junk data):
Area
0
1
2
3
...
90+
A
123
65
45
20
--
66
B
442
456
124
422
--
999
C
442
99
88
747
--
234
I need to group these figures into age bands (0-19. 20-39, 40-59...)
eg:
Area
0-19
20-39
40-59
60+
A
789
689
544
1024
B
1564
884
1668
1589
C
800
456
456
951
What is the best way to do this?
I could do a simple SUM as below, but that feels like a massive amount of script for something that feels like it should be straightforward.
SELECT
[0]+[1]+[2]+...[19] AS [0-19],
[20]+[21]+[22]+...[39] AS [20-39]
...
Is there a simpler way? I'm wondering if PIVOT can help but am struggling to visualise how to use it to get my desired result.
Hoping I'm missing something obvious!
EDIT This is how the data has been supplied to me, I know it's not a great table design but unfortunately that's out of my hands.
I would suggest creating a view on top of your table like so:
CREATE VIEW v_t_normal
SELECT Area, Age, Value
FROM t
CROSS APPLY (VALUES
(0, [0])
(1, [1])
...
(90, [90+])
) AS ca(Age, Value)
That view will normalize present your data in somewhat normalized form. You will not be able to edit the data in the view but you should be able to perform basic math and aggregation on the data. The 90+ value will still cause headache as it encapsulates more than one value.
I'm going to answer by suggesting an alternative table design which will make life easier:
Area | Age | Count
A | 0 | 123
A | 1 | 65
...
B | 0 | 442
Here we are storing each area's age in a separate record, rather than column. With this design in place, your ask is easy to come by using conditional aggregation:
SELECT
Area,
SUM(CASE WHEN Age BETWEEN 0 AND 19 THEN Count ELSE 0 END) AS [0-19],
SUM(CASE WHEN Age BETWEEN 20 AND 39 THEN Count ELSE 0 END) AS [20-39],
...
FROM yourNewTable
GROUP BY Area;
I have two tables. One holds a series of ranges (tbRange)eg
ID From To Score
1 0.00 17.00 A
2 17.00 22.50 B
3 22.50 24.50 C+
4 24.50 26.50 C
5 26.50 31.50 C-
6 31.50 44.00 D
the other table has a total value (tbValues) and an empty 'Score' field
BuildingID Totals Score
3065 22.10 NULL
3066 22.00 NULL
3067 23.86 NULL
I've been trying to query tbRange with an update query to ascertain and populate the tbValues.Score with the tbRange.Score where my tbValues.Totals lies between tbRange.From and tbRange.To but I can't get anywhere.
In the example 3 records above the desired outcome would be 'B', 'B', 'C+'
Thanks in advance
Try Using like this and let me know if it helps ?
update aa
set aa.Score = a.Score
from tbRange as a
inner join tbValues as aa
on aa.Totals BETWEEN a.[From] AND a.[To]
EDITS
I didn't noticed that there is two 24.0 so which grade will be implemented first ?
So basically the soluction to this is we can set if Total is >= a.from AND Total is < a.to so thats how it will look for a better value But its upto you if you want it or not.
update aa
set aa.Score = a.Score
from tbRange as a
inner join tbValues as aa
on aa.Totals >= a.[From] AND aa.Totals < a.[To]
IF IT WORKS THEN HOW IT WORK ??
In sql we have a BETWEEN operator that can be used to specific select between Ranges .
I have a table which contains a row for each day and number of hours an employee is employed.
Table 1
Employee Task Hours Date Sum (what I'm looking for)
A 123 4 1/1/2017 8
A 403 4 1/1/2017 8
B 123 3 1/1/2017 8
B 656 5 1/1/2017 8
A 303 1 1/2/2017 7
A 123 6 1/2/2017 7
What I am trying to do is take the sum of the Hours column grouped by Date. In other words, I want the sum of the Hours column where the Date = Date in the current row.
What you need is the EARLIER function.
The DAX for the calculated column is as follows:
Sum =
CALCULATE(
SUM(Table1[Hours]),
FILTER(
ALL(Table1) ,
Table1[Employee] = EARLIER(Table1[Employee]) &&
Table1[Date] = EARLIER(Table1[Date])
)
)
Result:
I don't think it's possible to make a new column, but you can achieve this using a measure.
Use the below DAX to create a measure and then use that in your visuals.
Sum = CALCULATE(Sum(Table1[Hours]), FILTER(ALL(Table1), Table1[Employee] = MAX(Table1[Employee]) && Table1[Date] = MAX(Table1[Date])))
I'm using SQL Server 2008.
I have a bunch of tables I'd like to put side-by-side based on ID, but they have different numbers of rows per id.
eg. Table 1:
ID Value1
1 'hello'
1 'world'
2 'random'
2 'words'
2 'exist'
4 'today'
Table 2:
ID Value2
1 25
3 30
3 12
4 11
4 10
4 52
What I would like is to add NAs up bulk them up to 4 entries per id (in this example, in the real one 25). So my output would be:
Table 3:
ID Value1 Value2
1 'hello' 25
1 'world' na
1 na na
1 na na
2 'random' na
2 'words' na
2 'exist' na
2 na na
3 na 30
3 na 12
3 na na
3 na na
4 'today' 11
4 na 10
4 na 52
4 na na
In the real scenario I have 12 different tables, each which may have any number of rows per id up to 25 (including 0 for some ids) and the rows per id can vary within the table on different ids too.
I'm not sure where to start here, I know how to join the tables together on id, and to leave all rows there, but not how to get 25 per id regardless of how many entries there are for any particular id.
Any advice would be much appreciated!
I am using DB2 and have the following table (Table A - 3 Columns) :
EmpNum YearMonth Value
100 201201 2
100 201207 1
100 201206 7
102 201201 8
102 201205 15
102 201207 4
… etc
I would like to produce a new Table B with one row per employee, and a column for each YearMonth.
I am hoping that I can generate the Table B 'YearMonth' column name dynamically from the data as there will be 120 columns.
The value would then be put in the cell with the associated YearMonth heading to give a table like this :
EmpNum 201201 201202 201203 201204 201205 201206 201207 etc ….
100 2 7 1
102 8 15 4
I have tried looking up 'Stored Procedures' and 'Dynamic Column Names' but cannot fine anything quite like this.
I have two questions :
Is this possible in DB2 ?
What should I look up for more information ?
Thanks in anticipation !
Ross
What you are looking for is called Pivot. Unfortunately, DB2 doesn't implement the PIVOT statement (unlike Oracle). So it will not be possible to create a query that creates a dynamic number of columns.
Have a look at Poor Man's SQL Pivot. List Questions as Columns and Answers per User in one row. That's the closest you can get to.
This is a generic procedure that allows to pivot a table: https://github.com/angoca/db2tools/blob/master/pivot.sql