Pivot without aggregation in SQL - sql

I am trying to figure out how to pivot column to row without aggregation.
I have a table with Account, Company Name and Company %. I am trying to pivot so that all companies info with respect to that account are on the same row. There isn't a limit on how many companies an account could have and I will need to include all companies.
Currently:
Account
Company Name
Company %
1
Company A
Company A%
1
Company B
Company B%
2
Company B
Company B%
3
Company A
Company A%
3
Company B
Company B%
3
Company K
Company K%
3
Company W
Company W%
Expected Results:
Account
Company 1
Company 1%
Company 2
Company 2%
Company 3
Company 3%
Company 4
Company 4%
1
Company A
Company A%
Company B
Company B%
2
Company B
Company B%
3
Company A
Company A%
Company B
Company B%
Company K
Company K%
Company W
Company W%

Any modern implementation of SQL has ROW_NUMBER() and that can be used for what you want.
It still uses MAX() to collapse multiple rows in to single rows, but it is being used as pick the one value that isn't NULL.
There is no sane reason to avoid its use.
WITH
sorted AS
(
SELECT
yourTable.*,
ROW_NUMBER() OVER (PARTITION BY account ORDER BY company_name) AS account_row_id
FROM
yourTable
)
SELECT
account,
MAX(CASE WHEN account_row_id = 1 THEN company_name END) AS company_name_1,
MAX(CASE WHEN account_row_id = 1 THEN company_pct END) AS company_pct_1,
MAX(CASE WHEN account_row_id = 2 THEN company_name END) AS company_name_2,
MAX(CASE WHEN account_row_id = 2 THEN company_pct END) AS company_pct_2,
MAX(CASE WHEN account_row_id = 3 THEN company_name END) AS company_name_3,
MAX(CASE WHEN account_row_id = 3 THEN company_pct END) AS company_pct_3,
MAX(CASE WHEN account_row_id = 4 THEN company_name END) AS company_name_4,
MAX(CASE WHEN account_row_id = 4 THEN company_pct END) AS company_pct_4
FROM
sorted
GROUP BY
account
ORDER BY
account

Related

Group rows while excluding null values on specific column and aggregating another

I have a table like this
CUSTOMER_ID
ALIAS_ID
ULTIMATE_NAME
MODEL_SUB_TYPE
OLD_PD
OLD_EXP
OLD_ECAP
RATING
Client A
123
Company A
CI_COM_KN
1
1
1
BB+
Client A
123
Company A
CI_POL_KN
0.5
1
1
null
Client A
456
Company B
CI_COM_KN
1
1
3
BB+
Client A
456
Company B
CI_POL_KN
0.5
1
3
null
What I need my query to do is to ignore the values in OLD_PD, OLD_EXP and RATING columns when MODEL_SUB_TYPE = Sub_type B, and aggregate (sum) the OLD_ECAP column regardless of MODEL_SUB_TYPE.
What I have so far is this:
SELECT
CUSTOMER_ID,
ALIAS_ID,
SUBSTR(ULTIMATE_NAME, 0, 70) as ULTIMATE_NAME,
MODEL_SUB_TYPE,
CASE
WHEN MODEL_SUB_TYPE LIKE 'CI_COM_%' THEN ULTIMATE_POD
END AS OLD_PD,
SUM(
CASE
WHEN MODEL_SUB_TYPE LIKE 'CI_COM_%' THEN CREDIT_LIMIT_NET_EXPOSURE
END
) AS OLD_EXP,
SUM(EC_CONSUMPTION_ND) AS OLD_ECAP,
ULTIMATE_RATING AS RATING
FROM
CALC6619.SO_REPORTING -- OLD QUARTER --
WHERE
MODEL_TYPE LIKE 'IR'
AND MODEL_SUB_TYPE LIKE 'CI_%'
AND CUSTOMER_ID = '09781C1 01' -- Customer ID
GROUP BY
CUSTOMER_ID,
ALIAS_ID,
ULTIMATE_NAME,
MODEL_SUB_TYPE,
ULTIMATE_POD,
ULTIMATE_RATING
What I want is my query to return a table like this (based on table above):
CUSTOMER_ID
ALIAS_ID
ULTIMATE_NAME
MODEL_SUB_TYPE
OLD_PD
OLD_EXP
OLD_ECAP
RATING
Client A
123
Company A
CI_COM_KN
1
1
2
BB+
Client A
456
Company B
CI_COM_KN
1
1
6
BB+
But it's actually returning a table like the first one, but with null values where it's supposed to be, but not grouping the rows per company ID, like so:
CUSTOMER_ID
ALIAS_ID
ULTIMATE_NAME
MODEL_SUB_TYPE
OLD_PD
OLD_EXP
OLD_ECAP
RATING
Client A
123
Company A
CI_COM_KN
1
1
1
BB+
Client A
123
Company A
CI_POL_KN
null
null
1
null
Client A
456
Company B
CI_COM_KN
1
1
3
BB+
Client A
456
Company B
CI_POL_KN
null
null
3
null
You just have to remove the columns from group by and do some changes in SELECT clause as follows:
SELECT
CUSTOMER_ID,
ALIAS_ID,
SUBSTR(ULTIMATE_NAME, 0, 70) as ULTIMATE_NAME,
MAX(CASE WHEN MODEL_SUB_TYPE LIKE 'CI_COM_%' THEN MODEL_SUB_TYPE END) AS MODEL_SUB_TYPE,
SUM(CASE
WHEN MODEL_SUB_TYPE LIKE 'CI_COM_%' THEN ULTIMATE_POD
END) AS OLD_PD,
SUM(
CASE
WHEN MODEL_SUB_TYPE LIKE 'CI_COM_%' THEN CREDIT_LIMIT_NET_EXPOSURE
END
) AS OLD_EXP,
SUM(EC_CONSUMPTION_ND) AS OLD_ECAP,
MAX(ULTIMATE_RATING) AS RATING
FROM
CALC6619.SO_REPORTING -- OLD QUARTER --
WHERE
MODEL_TYPE LIKE 'IR'
AND MODEL_SUB_TYPE LIKE 'CI_%'
AND CUSTOMER_ID = '09781C1 01' -- Customer ID
GROUP BY
CUSTOMER_ID,
ALIAS_ID,
SUBSTR(ULTIMATE_NAME, 0, 70)

T-SQL - Pivot out Distinct N rows for each group

I have a table similar to the one below with customers, products, and purchase date. I am trying to get a list of customers and their 3 most recently purchased DISTINCT products. I want to use purchase date as a means of ordering the results, but I don't want to see duplicate product IDs.
Customer
Product
PurchaseDate
1
a
2020-12-5
2
b
2020-12-5
1
a
2020-12-4
2
a
2020-12-3
1
b
2020-12-2
2
b
2020-12-1
1
c
2020-11-30
1
d
2020-11-29
2
b
2020-11-28
Ideally I would see results like this
Customer
Product1
Product2
Product3
1
a
b
c
2
b
a
I have tried partition by statements and order by statements, but everything wants me to include date in the final output. Is there a way to do this?
Most recent distinct products is tricky. This requires one level of aggregation per customer and product and then another for pivoting:
select customer,
max(case when seqnum = 1 then product end) as product_1,
max(case when seqnum = 2 then product end) as product_2,
max(case when seqnum = 3 then product end) as product_3
from (select customer, product, max(purchasedate) as max_purchasedate,
row_number() over (partition by customer order by max(purchasedate) desc) as seqnum
from t
group by customer, product
) cp
group by customer;

Creating separate columns based on the main column in a sql table.?

I have a table with thousands of record which has a structure like below :
Street
House
Persons
1
A
2
1
B
5
1
C
3
2
D
6
2
E
9
3
F
4
I want to frame a sql query such that its output will be like:
Street
House
Persons
House
Persons
House
Persons
1
A
2
B
5
C
3
2
D
6
E
9
null
null
3
F
4
null
null
null
null
The number of house in a street is not the same for all the streets and it varies based on the street.
Can someone please help me in framing this query? Thanks!
For a fixed maximum number of rows per street, you can use window functions and aggregation:
select street,
max(case when rn = 1 then house end) as house1,
max(case when rn = 1 then persons end) as persons1,
max(case when rn = 2 then house end) as house2,
max(case when rn = 2 then persons end) as persons2
from (
select t.*,
row_number() over(partition by street order by house) rn
from mytable t
) t
group by street
You can add more conditional expressions to the select clause to handle more rows per street.

Sql Grouping Query

I'm wondering how i can get a query to put these groupings into one line so i can put it into a vb.net datagrid.
For example Number, Company Name, Current, 31-60, 61-90
Which would be for example company A, but get the grouping to all be on one line.
104680777, Company A, 643546.344, 34534534.77, 3454.55
To even get this query below. I had to do this.
select sum(Amount), DunsNum, CompanyName, Age
from tblARAged
group by DunsNum, Age, CompanyName
Amount Num CompanyName Age
63546.344 104680777 Company a 1
34534534.77 104680777 Company a 2
3454.55 104680777 Company a 3
3453453.66 186830733 Company b 1
345342.45 186830733 Company b 2
4542.55 186830733 Company c 3
3434.55 26409797 Company c 1
345345 26409797 Company c 2
The 1 correlates to current, 2 correlates to 31-60 and 3 correlates to 61-90 for age
I would do what Nimesh stated, though I would make a few tweaks. You want to do aggregation as late as possible:
SELECT DunsNum ,
CompanyName ,
SUM(CASE WHEN ( Age = 1 ) THEN Amt
ELSE 0
END) AS [Amount_Cur] ,
SUM(CASE WHEN ( Age = 2 ) THEN Amt
ELSE 0
END) AS [Amount_31-60] ,
SUM(CASE WHEN ( Age = 3 ) THEN Amt
ELSE 0
END) AS [Amount_61-90]
FROM tblARAged
GROUP BY DunsNum ,
CompanyName;
I haven't tested this code

Count without nested select: is this possible?

Database:
Department Position Points
A Manager 50
A Supervisor 10
A Supervisor 10
A Staff 2
A Staff 2
B Manager 40
B SuperVisor 8
B Staff 2
B Staff 2
B Staff 2
Desired query result:
Dept Manager Count Supervisor Count Staff Count Staff Total Pts
A 1 2 2 4
B 1 1 3 4
Is the desired query result possible without using nested select with count?
We have a certain stored procedure similar to this using nested counts and we like to make it simpler and perform better/faster
Use Conditional Aggregate to count only the specific data
Select Department,
count(case when Position = 'Manager' then 1 END) as Manager,
count(case when Position = 'Supervisor' then 1 END) as Supervisor,
count(case when Position = 'Staff' then 1 END) as Staff
From yourtable
Group by Department
If you are using Sql Server use this
SELECT Department,
Manager,
Supervisor,
Staff
FROM Yourtable
PIVOT (Count(Position)
FOR Position IN (Manager,Supervisor,Staff))pv
Use conditional SUM:
SELECT Department,
SUM(CASE WHEN Position = 'Manager' THEN 1 END) as Manager,
SUM(CASE WHEN Position = 'Supervisor' THEN 1 END) as Supervisor,
SUM(CASE WHEN Position = 'Staff' THEN 1 END) as Staff
FROM yourtable
GROUP BY Department
Or You can use PIVOT operator:
select Detartment, Manager, Supervisor, Staff
from yourtable
pivot (count(Position) for Position in (Manager, Supervisor, Staff)) Result