Transposing Rows into Multiple columns SQL Server - sql

I have a table with multiple rows that needs transposed to one row with multiple columns. The order in which the items are listed on my current table matters for ranking purposes, so I need them to stay in order when they are transposed into columns
Thanks in advance

You can use row_number() & do conditional aggregation :
SELECT individuaid,
MAX(CASE WHEN seq = 1 THEN item_no END) item_no_1,
MAX(CASE WHEN seq = 1 THEN HL2_CODE END) HL_2_1,
. . . .
FROM (SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY individuaid ORDER BY item_no) AS seq
FROM table t
) T
GROUP BY individuaid;

Related

SQL help to insert unique values

I need to insert the Unique combination of Ticker, Dividend_Pay_Date to another table. If I find duplicate data I need to select only the Dividend_type_marker_description = 'Final' row. I am showing example of source data where I have duplicate data for Ticker ABC.
I have noticed Dividend_type_marker_description = '2nd Interim' also for same date-ticker combination. But no more than 3 status
I would appreciate any help with this.
I think row_number() does what you want:
select . . .
from (select t.*,
row_number() over (partition by ticker, dividend_pay_rate
order by (case when Dividend_type_marker_description = 'Final' then 1 else 2 end)
) as seqnum
from t
) t
where seqnum = 1;

How do I create a new SQL table with custom column names and populate these columns

So I currently have an SQL statement that generates a table with the most frequent occurring value as well as the least frequent occurring value in a table. However this table has 2 rows with the row values as well as the fields. I need to create a custom table with 2 columns with min and max. Then have one row with one value for each. The value for these columns needs to be from the same row.
(SELECT name, COUNT(name) AS frequency
FROM firefighter_certifications
GROUP BY name
ORDER BY frequency DESC limit 1)
UNION
(SELECT name, COUNT(name) AS frequency
FROM firefighter_certifications
GROUP BY name
ORDER BY frequency ASC limit 1);
So for the above query I would need the names of the min and max values in one row. I need to be able to define the name of new columns for the generated SQL query as well.
Min_Name | Max_Name
Certif_1 | Certif_2
I think this query should give you the results you want. It ranks each name according to the number of times it appears in the table, then uses conditional aggregation to select the min and max frequency names in one row:
with cte as (
select name,
row_number() over (order by count(*) desc) as maxr,
row_number() over (order by count(*)) as minr
from firefighter_certifications
group by name
)
select max(case when minr = 1 then name end) as Min_Name,
max(case when maxr = 1 then name end) as Max_Name
from cte
Postgres doesn't offer "first" and "last" aggregation functions. But there are other, similar methods:
select distinct first_value(name) over (order by cnt desc, name) as name_at_max,
first_value(name) over (order by cnt asc, name) as name_at_min
from (select name, count(*) as cnt
from firefighter_certifications
group by name
) n;
Or without any subquery at all:
select first_value(name) over (order by count(*) desc, name) as name_at_max,
first_value(name) over (order by count(*) asc, name) as name_at_min
from firefighter_certifications
group by name
limit 1;
Here is a db<>fiddle

Using window function in redshift to aggregate conditionally

I have a table with following data:
Link to test data: http://sqlfiddle.com/#!15/dce01/1/0
I want to aggregate the items column (using listagg) for each group in gid in sequence as specified by seq column based on the condition that aggregation ends when pid becomes 0 again for a group.
i.e.
for group g1, there would be 2 aggregations; 1 for seq 1-3 and another for sequence 4-6; since for group g1, the pid becomes 0 for seq 4.
I expect the result for the given example to be as follows (Please note that seq in result is the min value of seq for the group where the pid becomes 0):
I understand your question as a gaps and island problem, where you want to group together adjacent rows having the same gid untiil a pid having value 0 is met.
Here is one way to solve it using a window sum to define the groups: basically, a new island starts everytime a pid of 0 is met. The rest is just aggregation:
select
gid,
min(seq) seq,
listagg(items, ',') within group(order by seq) items
from (
select
t.*,
sum(case when pid = 0 then 1 else 0 end) over(partition by gid order by seq) grp
from mytable t
) t
group by gid, grp
order by gid, grp
it's gaps and islands problem:
with
subgroup_ids as (
select *, sum(case when pid=0 then 1 else 0 end) over (partition by gid order by seq) as subgroup_id
from tablename
)
select gid, subgroup_id, listagg(items,',')
from subgroup_ids
group by 1,2

Presto SQL - Rank Multiple Conditions for Multiple Columns

I am trying to write a single query (if possible) to rank ids based on multiple conditions.
My table is like this:
id group subgroup value
1 A Q 12
2 A Z 10
3 B Z 14
4 A Z 20
5 B W 20
I tried this query:
SELECT id,
CASE WHEN group = 'A' THEN ROW_NUMBER() OVER (PARTITION BY group ORDER BY SUM(value) DESC) AS rank_group
CASE WHEN group = 'A' AND subgroup = 'Z' THEN ROW_NUMBER() OVER (PARTITION BY group, subgroup ORDER BY SUM(value) DESC) AS rank_subgroup
FROM table
GROUP BY group, subgroup
But ended up with something like this:
id rank_group rank_subgroup
1 1 1
1 2 2
I would like to get each distinct id and return the rank based on the conditions of the case statement, but it looks like adding the needed partition causes a multiplication as the group by is necessary. I could write individual queries for each column, but I'd like to avoid if possible.
Do you want something like this?
select t.*,
dense_rank() over (order by sumg, group),
dense_rank() over (partition by group order by sumsg, subg),
from (select t.*,
sum(value) over (partition by group) as sumg,
sum(value) over (partition by group, subgroup) as sumsg
from t
) t;
This is my best guess at interpreting what you might want.

Organizing SQL data based on date

I am trying to organize my SQL data based off of the dates from which the orders were made.
My data:
SELECT DISTINCT ORDER_NO, ITEM, VERSION_NO,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY ORDER_NO ORDER BY NOT_BEFORE_DATE
ASC) = 1
THEN 'what-if'
ELSE 'wh'
END) AS VERSION_NEW
,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY ORDER_NO ORDER BY
NOT_BEFORE_DATE ASC) = 2
THEN 'initial'
ELSE 'other'
END) AS VERSION
FROM FDT_MAPTOOL
WHERE ITEM IN (1032711)
;
My results:
I want my data to be ordered by PO# and the date it was created.
As you can see in my picture the First two line have the same ITEM and same PO (Order_No). I need the first two to say Initial on the side because they are the first two based on the dates. They were created first. Everything after should say other.
I am not sure if PL/SQL is needed for this?
Thank you!
Use a different analytic function so that more than one row can have the value of 1 e.g.
SELECT DISTINCT ORDER_NO, ITEM, VERSION_NO,
(CASE WHEN DENSE_RANK() OVER (PARTITION BY ORDER_NO ORDER BY NOT_BEFORE_DATE
ASC) = 1
THEN 'what-if'
ELSE 'wh'
END) AS VERSION_NEW
,
(CASE WHEN DENSE_RANK() OVER (PARTITION BY ORDER_NO ORDER BY
NOT_BEFORE_DATE ASC) = 1
THEN 'initial'
ELSE 'other'
END) AS VERSION
FROM FDT_MAPTOOL
WHERE ITEM IN (1032711)
;
Either rank() OR dense_rank() should work here instead of row_number()
nb: note sure if you really need "select distinct"