SQL view on table to combine rows into additional columns - sql

This has stumped me a little, I have a table like this
Id
Address
Address 1
Postcode
1
1 straight street
4 corners
BL51 ANK
1
46 Double Close
Some Place
ZE12 7TB
2
7 The Fields
Farmland
FA7 5ME
I need to create a view that will produce this result:
Id
Address
Address 1
Postcode
Address
Address 1
Postcode
1
1 straight street
4 corners
BL51 ANK
46 Double Close
Some Place
ZE12 7TB
2
7 The Fields
Farmland
FA7 5ME
So basically based on the ID there can be between 4 and 50 rows, I need this returning as a single row with multiple columns containing the different data. I didn't want to do 50 joins as I'm sure there is a smarter way to do this.
Any help is much appreciated.

You can use conditional aggregation (or pivot). Simpler and faster than 50 joins, but still cumbersome:
select id,
max(case when seqnum = 1 then address end),
max(case when seqnum = 1 then address1 end),
max(case when seqnum = 1 then postcode end),
max(case when seqnum = 2 then address end),
max(case when seqnum = 2 then address1 end),
max(case when seqnum = 2 then postcode end),
. . .
max(case when seqnum = 50 then address end),
max(case when seqnum = 50 then address1 end),
max(case when seqnum = 50 then postcode end)
from (select t.*,
row_number() over (partition by id order by (select null)) as seqnum
from t
) t
group by id;
The code is pretty repetitive, so it is simple to generate it in a spreadsheet.

Related

Remove duplicates from query

I have the below table
item
area
qty
item 1
a
10
item 1
b
17
item 2
b
20
item 3
a
10
item 2
c
8
I am looking to have a result in SQL as below (a unique item and a unique area):
item
area a
area b
area c
item 1
10
17
0
item 2
0
20
8
item 3
10
0
0
i do have this query which not giving me what am looking for if the area has been changed or increased also its for 2 columns table not 3 columns:
select
item,
max(case when seqnum = 1 then area end) as area_1,
max(case when seqnum = 2 then area end) as area_2,
max(case when seqnum = 3 then area end) as area_3
from (
select A.*,
row_number() over (partition by item order by area) as seqnum
from A
) A
group by item;
Looking forwards to your kind help.
If you have a fixed list of areas, then no need for window functions ; you can explicitly filter on each individual value in max().
Another fix to your query is to take the max of qty rather than of area (whose value is already filtered).
select item,
coalesce(max(case when area = 'a' then qty end), 0) as area_a,
coalesce(max(case when area = 'b' then qty end), 0) as area_b,
coalesce(max(case when area = 'c' then qty end), 0) as area_c
from mytable
group by item

Transpose multiple rows to multiple columns with no aggregate using T-SQL

Users have multiple certificates which might be of 3 different types. They may hold multiple certificates of those types. I would like to put them into a single record anticipating that they will have a max of five certificates of each type.
I've written a query that will find the type and put its information into an appropriately named column but still get one row per certificate.
Data shape is:
Name, cert_Type, Cert Name, cert_State, Cert_Expiration
JOE, Equipment, NULL, Operator, 01/30/2022
JOE Equipment, Rigger, 12/31/2021
JOE License, Maryland, 08/12/2025
I'm doing a group by, but still need some aggregating function to get the desired result which might look like this:
| UserName| userID|Cred_Type_1|Cred_1|Type_1_Cred_1_ Expires|Type_1_Cred_2|Type_1_Cred_2_Expires|Cred_type_2|Type2_State |Type_2_expires|
| ----------- | ----------- |-------------|-------------|------------|------------|-----------|-----------|---|---|
|Joe|123|Equipment|Operator|01/30/2022|Rigger|12/31/2021|License | Maryland|08/12/2025|
Note that there is no aggregate here, not counting or averaging or summing. Is there another aggregate function that will do this?
If I understand correctly, you can use row_number() and conditional aggregation:
select userid, username,
max(case when seqnum = 1 then cert_type end),
max(case when seqnum = 1 then cert_name end),
max(case when seqnum = 1 then cert_state end),
max(case when seqnum = 1 then cert_expiration end),
max(case when seqnum = 2 then cert_type end),
max(case when seqnum = 2 then cert_name end),
max(case when seqnum = 2 then cert_state end),
max(case when seqnum = 2 then cert_expiration end),
max(case when seqnum = 3 then cert_type end),
max(case when seqnum = 3 then cert_name end),
max(case when seqnum = 3 then cert_state end),
max(case when seqnum = 3 then cert_expiration end),
from (select t.*,
row_number() over (partition by userid order by cert_expiration desc) as seqnum
from t
) t
group by userid, username;

Split ROWS into multiple COLUMN

I have some information on student name and their roll no -
And I want to split them into 3 sets of column like below. The total no of rows should always be ceiling value of (# of rows/3)
You can do this with conditional aggregation. However, SQL tables represent unordered sets, so which values end up where is arbitrary:
select max(case when seqnum % 3 = 0 then name end) as name_1,
max(case when seqnum % 3 = 0 then roll end) as roll_1,
max(case when seqnum % 3 = 1 then name end) as name_2,
max(case when seqnum % 3 = 1 then roll end) as roll_2,
max(case when seqnum % 3 = 2 then name end) as name_3,
max(case when seqnum % 3 = 2 then roll end) as roll_3
from (select t.*, row_number() over (order by (select null)) - 1 as seqnum
from t
) t
group by floor(seqnum / 3);
If you have an ordering column, then use it instead of (select null).

Oracle SQL: how to merge n lines and create additional columns in result?

Table:
id race
1 elf
1 troll
2 lizard
2 elf
2 human
3 dwarf
I am looking for a request that output this:
id race1 race2 race3
1 elf troll
2 lizard elf human
3 dwarf
There can be n race or a given max number of races if it's more easy
Is this possible with an sql query (not pl/sql)? (oracle if special function is needed)
You can use conditional aggregation if you want to do this in a simple select:
select id,
max(case when seqnum = 1 then race end) as race_1,
max(case when seqnum = 2 then race end) as race_2,
max(case when seqnum = 3 then race end) as race_3,
max(case when seqnum = 4 then race end) as race_4,
max(case when seqnum = 5 then race end) as race_5
from (select t.*,
row_number() over (partition by id order by id) as seqnum
from t
) t
group by id;

need to convert data in multiple rows with same ID into 1 row with multiple columns

I reviewed versions of my question already addressed, but some of the good tips I found (using rank() over (partition...) for example, do not seem to work in the Sybase version I am on.
I am hoping to run a procedure that pulls data organized as follows:
Email | Preference
email1 | PreferenceXYZ
email1 | PreferenceABC
And render it in a table like the following:
Email | Preference1 | Preference2
email1 | PreferenceXYZ | PreferenceABC
In essence, I have multiple records for the same person (best identified via email record as a unique identifier) and I want to capture these multiple preferences for a given user and create 1 individual record per user (per email).
If you only have two preferences, then you can use min() and max():
select email, min(preference) as preference1,
(case when min(preference) <> max(preference) then max(preference) end) as preference2
from t
group by email;
EDIT:
If you have up to seven values, then pivot using row_number():
select email,
max(case when seqnum = 1 then preference end) as preference1,
max(case when seqnum = 2 then preference end) as preference2,
max(case when seqnum = 3 then preference end) as preference3,
max(case when seqnum = 4 then preference end) as preference4,
max(case when seqnum = 5 then preference end) as preference5,
max(case when seqnum = 6 then preference end) as preference6,
max(case when seqnum = 7 then preference end) as preference7
from (select t.*, row_number() over (partition by email order by preference) as seqnum
from t
) t
group by email;
EDIT II:
You can actually do this with a correlated subquery instead of row_number():
select email,
max(case when seqnum = 1 then preference end) as preference1,
max(case when seqnum = 2 then preference end) as preference2,
max(case when seqnum = 3 then preference end) as preference3,
max(case when seqnum = 4 then preference end) as preference4,
max(case when seqnum = 5 then preference end) as preference5,
max(case when seqnum = 6 then preference end) as preference6,
max(case when seqnum = 7 then preference end) as preference7
from (select t.*,
(select count(*)
from t t2
where t2.email = t.email and
t2.preference <= t.preference
) as seqnum
from t
) t
group by email;