Changing SQL output with similar ITEM_ID - mysql

With my SQL query I get the following output:
My Output
ITEM_ID USP_NO Value
2616761 1 Type Bijtafel
2616761 2 Materiaal Steen
2616761 3
2616761 4
2616761 5
5037554 1 Materiaal Geïmpregneerd hout
5037554 2
5037554 3
But I want to convert my output to have a single ITEM_ID with in different columns the values like the following
ITEM_ID USP1 USP2
2616761 Type Bijtafel Materiaal Steen
5037554 Materiaal Geïmpregneerd hout
My Query is the following:
SELECT *
FROM PIM_USP
where item_ID IN (SELECT Item_ID
from PIM_ITEM where
PIM_ITEM.brick_ID=10002084)

You want conditional aggregation :
SELECT ITEM_ID,
MAX(CASE WHEN USP_NO = 1 THEN Value END) AS USP1,
MAX(CASE WHEN USP_NO = 2 THEN Value END) AS USP2,
MAX(CASE WHEN USP_NO = 3 THEN Value END) AS USP3,
MAX(CASE WHEN USP_NO = 4 THEN Value END) AS USP4,
MAX(CASE WHEN USP_NO = 5 THEN Value END) AS USP5
FROM PIM_USP p
GROUP BY ITEM_ID;

Related

Postgres - How to search and aggregate from a JSON column

I have an asset_quantities table as below
id | asset_type | quantity | site_id | asset_ids_json
1 'Container' 3 1 [{"id":1,"make":"am1","model":"amo1"},{"id":2,"make":"am1","model":"amo2"},{"id":3,"make":"am3","model":"amo3"}]
2 'Cage' 3 1 [{"id":4,"make":"bm1","model":"bmo1"},{"id":5,"make":"bm2","model":"bmo2"},{"id":6,"make":"bm2","model":"cmo3"}]
3 'Crate' 3 1 [{"id":7,"make":"cm1","model":"cmo1"},{"id":8,"make":"cm1","model":"cmo1"},{"id":9,"make":"cm1","model":"cmo2"}]
I want to write a SQL query in Postgres that will give me the quantity count of each asset type for a given make or model.
E.g. If I wanted to fetch the quantity for each asset type where make='am1',
site_id | Container_qty | Cage_qty | Crate_qty
1 2 0 0
E.g. If I wanted to fetch the quantity for each asset type where make='cm1', the result set would look like
site_id | Container_qty | Cage_qty | Crate_qty
1 0 0 3
I have written the query below to pivot the values from the 'asset_type' rows into columns but can't figure out how to filter and aggregate the counts based on the attributes inside the field 'asset_ids_json'. It is safe to assume that the length of the json array inside asset_ids_json will always be the same as the value in the 'quantity' column.
select
aq.site_id,
sum(case when aq.asset_type = 'Container' then aq.quantity end) container_qty,
sum(case when aq.asset_type = 'Cage' then aq.quantity end) cage_qty ,
sum(case when aq.asset_type = 'Crate' then aq.quantity end) crate_qty,
from asset_quantities aq
group by aq.site_id;
The crux of my question is how can I filter & aggregate results based on the attributes inside the json column 'asset_ids_json'. I'm using Postgres 9.4.
step-by-step demo:db<>fiddle
SELECT
site_id,
SUM(case when asset_type = 'Container' then quantity end) container_qty,
SUM(case when asset_type = 'Cage' then quantity end) cage_qty ,
SUM(case when asset_type = 'Crate' then quantity end) crate_qty
FROM (
SELECT DISTINCT ON (id)
site_id,
asset_type,
quantity
FROM asset_quantities aq,
json_array_elements(asset_ids_json)
WHERE value ->> 'make' = 'cm1'
) s
GROUP BY site_id
To get a WHERE clause over the content of a JSON array you have to expand the array. json_array_elements() creates one row for each element. With that it is possible to ask for a certain value.
Because of this expansion the current rows are multiplied (three times here because there are three elements in the array). Because you are only interested in the original site_id, asset_type and quantity data which were simply copied into the new records, you can eliminate them with a DISTINCT. DISTINCT ON checks for distinct values of each id. So if two JSON array would contain the same key/value both will be saved.

Merge multiple rows in single row in mysql view

I have a mysql view on which 1 column is repeated on 4 rows but the other column has different values. I want to merge all 4 rows into 1 by giving columns custom names.
Example:
I have Long_Desc repeated in 4 rows with different Nutr_Val and Nutr_No. I want to combine all 4 rows so the table will look like
NDB_No | Nutr_No | Nutr_Val | Long_Desc | PROCNT | FAT | CHODCDF | ENERC_KCAL
So I have Nutr_Val adjusted in those last 4 columns.
This could be solved with conditional aggregation :
SELECT
t.nbd_no,
t.nutr_no,
t.nutr_val,
t.long_desc,
MAX(CASE WHEN t.tagname = 'PROCNT' THEN t.fdgrp_cd END) PROCNT,
MAX(CASE WHEN t.tagname = 'FAT' THEN t.fdgrp_cd END) FAT,
MAX(CASE WHEN t.tagname = 'CHODCDF' THEN t.fdgrp_cd END) CHODCDF,
MAX(CASE WHEN t.tagname = 'ENERC_KCAL' THEN t.fdgrp_cd END) ENERC_KCAL
FROM mytable t
GROUP BY
t.nbd_no,
t.nutr_no,
t.nutr_val,
t.long_desc

combine multiple rows into one rows with several column

hello im going to select and group by with field x but showing in one row with several column
SELECT * FROM `cityname`
WHERE `city`='mashhad'
group by `city`,`number`
ORDER BY `city`
but i want showing :
mashhad 935 915 937 901
Since you want to all number of each city, and display all the number in separated columns, this will be a table pivot issue, try following query:
SELECT city,
MAX(CASE WHEN number = 935 THEN number ELSE NULL END) AS number_935,
MAX(CASE WHEN number = 915 THEN number ELSE NULL END) AS number_915,
MAX(CASE WHEN number = 937 THEN number ELSE NULL END) AS number_937,
MAX(CASE WHEN number = 901 THEN number ELSE NULL END) AS number_901
FROM cityname
GROUP BY city
Demo Here

Group by, converting rows to columns with no aggregate

I need to group the table during my query, and up until know I was doing that after querying - with the code as my group is quite complicated. But with the new data it appears to take minutes, and I'm thinking is there better way.
My current query results in this:
FKId | Name | A | B | C
1 Alpha 2 3 2
1 Beta 2 5 7
2 Alpha 8 1 10
2 Beta 7 -5 6
2 Gamma 1 2 3
And I convert it to this:
FKId | Alpha[A] | Alpha[B] | Alpha[C] | Beta[A] | Beta[B] | Beta[C] | Gamma[A] | Gamma[B] | Gamma[C]
1 2 3 2 2 5 7
2 8 1 10 7 -5 6 1 2 3
Is it possible to do with SQL? (and I assume it should be much faster than if I do this with code)
The names can be anything
I have very big number of colums A, B, C (like 20 - 30). The number of result columns can easily go to thousands as average project has about 100 names.
I have like 10-20 columns that I should group by, but doing a single group by FKId is fine - these columns are the same.
We use different SQL DBs, so I cannot use specific functions like PIVOT. I know that we used MySQL, MsSQL and SQLite a lot
We use NHibernate if it makes any difference.
I would also honor the solution done for MySQL if specific functions are used. We use it in 80% and it will already greatly improve the average performance if I could do that at least for MySQL.
Basically, you want to transpose the data. Here is what you can try. It should work across all databases but you need to know the columns A, B, C, etc beforehand:
create table my_table (
fkid integer,
name varchar(10),
a integer,
b integer,
c integer
);
insert into my_table values(1,'alpha',2,3,2)
,(1,'beta',2,5,7)
,(2,'alpha',8,1,10)
,(2,'beta',7,-5,6)
,(2,'gamma',1,2,3);
select fkid
, max(case when name = 'alpha' then a else null end) as alphaa
, max(case when name = 'alpha' then b else null end) as alphab
, max(case when name = 'alpha' then c else null end) as alphac
, max(case when name = 'beta' then a else null end) as betaa
, max(case when name = 'beta' then b else null end) as betab
, max(case when name = 'beta' then c else null end) as betac
, max(case when name = 'gamma' then a else null end) as gammaa
, max(case when name = 'gamma' then b else null end) as gammab
, max(case when name = 'gamma' then c else null end) as gammac
from my_table
group by fkid;

Join tables and get the same column to more columns based on the value

Lets say I join two tables and get a result like
id vendor vendor_id quantity
1 Sony 1 25
1 Apple 2 12
1 HTC 3 5
And I want the result to be like
id Quantity_Sony Quantity_Apple Quantity_HTC
1 25 12 5
How can I do that, I use Left joins to join the tables. I use mySql
SELECT ID,
MAX(CASE WHEN vendor = 'Sony' THEN Quantity END) Quantity_Sony,
MAX(CASE WHEN vendor = 'Apple' THEN Quantity END) Quantity_Apple,
MAX(CASE WHEN vendor = 'HTC' THEN Quantity END) Quantity_ATC
FROM
(
-- add your existing query here
) x
GROUP BY ID