PostgreSQL Crosstab Select Query - sql
Does any one know how to create crosstab queries in PostgreSQL?
For example I have two following tables:
TABLE A
| ID 1 | ID 2 | ID 3 |
|:-----------|------------:|:------------:|
| 00001 | 01 | 0001 |
| 00001 | 02 | 0001 |
| 00001 | 01 | 0002 |
TABLE B
| ID 1 | ID 2 | ID 3 | price | tax_rate |
|:-----------|------------:|:------------:|:------------:|:------------:|
| 00001 | 01 | 0001 |5000 | 8 |
| 00001 | 01 | 0001 |6000 | 10 |
I would like the query to return the following crosstab:
| ID 1 | ID 2 | ID 3 | price_8 | price_10 |
|:-----------|------------:|:------------:|:------------:|:------------:|
| 00001 | 01 | 0001 |5000 | 6000 |
| 00001 | 02 | 0001 |null | null |
| 00001 | 01 | 0002 |null | null |
Is this possible?
Try this -
SELECT * FROM crosstab(
'SELECT A.ID1, A.ID2, A.ID3, B.PRICE, B.TAX_RATE
FROM A
LEFT JOIN B
ON A.ID1 = B.ID1
AND A.ID2 = B.ID2
AND A.ID3 = B.ID3') AS
FINAL_RESULT (ID1 TEXT, ID2 TEXT, ID3 TEXT, PRICE_8 NUMERIC, PRICE_9 NUMERIC);
Here is a sample for your tables:
SELECT split_part(id, '.', 1) AS id1,
split_part(id, '.', 2) AS id2,
split_part(id, '.', 3) AS id3,
price_8, price_10
FROM crosstab(
'select id1||''.''||id2||''.''||id3 as id, cast(tax_rate as text) as taxRate, price
from (select * from Table1 natural left join Table2
order by 1,2,3) t'
)
AS ct (
id text,
price_8 int,
price_10 int
);
Related
SQL - Join two tables and conditionally select rows based on value from a categorical column
I have two tables with inner join. I have to conditionlly select only one row from right table based on the existence of a value in categorical column. Condition: If blue exists, select blue else select green Table-A: | ID | Name | | ---| ------| | 01 | row | | 02 | row | | 03 | row | Table-B: | ID | CatCol | | ---| --------| | 01 | blue | | 01 | green | | 01 | red | | 02 | green | | 02 | red | | 03 | blue | Expected: | ID | CatCol | | ---| --------| | 01 | blue | | 02 | green | | 03 | blue |
Consider below approach select a.ID, string_agg(CatCol, '' order by if(CatCol = 'blue', 1, 2) limit 1) CatCol from table_a a left join table_b b on a.ID = b.ID and CatCol in ('blue', 'green') group by ID if applied to sample data in your question - output is
This should work for you: SELECT b.ID, MIN(b.CatCol) as CatCol FROM table_b b INNER JOIN table_a a ON b.id = a.id GROUP BY b.ID
SQL query to get counts from two tables
I need help to write a query to combine two tables in order to get desired result set with count of rows. Please see below in detail: I have two tables Table A | CompanyID | ProductID | ProductPartsID | | --------- | --------- | -------------- | | 123 | ert | q1234 | | 234 | dfr | u678 | | 234 | dfr | Jdsdj | | 234 | dfr | Eewe | | 234 | dfr | dssd | | 234 | HJU | iui89 | | 234 | HJU | dfsfs | | 675 | gfd | 654 | | 675 | tyh | 765 | Table B |CompanyID | ProductID | |--------- |-----------| | 123 | ert | | 234 | dfr | | 234 | HJU | | 675 | gfd | | 709 | tgh | | 780 | 789 | Resultset Both tables has millions of records in reality. |CompanyID | #ofTableAProductPartsID | #ofTableBProductPartsID | |--------- |-------------------------|-------------------------| | 123 | 1 | 1 | | 234 | 6 | 2 | | 675 | 2 | 1 | e.t.c Table B does not have ProductPartsID, but it can be taken from TableA for ProductID from TableB.
using left join and group by : SELECT t.CompanyID , COUNT(t.ProductPartsID) , COUNT(DISTINCT t2.ProductID) FROM TABLE1 AS t LEFT JOIN Table2 t2 ON t.CompanyID = t2.CompanyID AND t.ProductID = t2.ProductID GROUP BY t.CompanyID
with TableAPartsCount as ( select A.CompanyID, count(A.ProductID) as #ofTableAProductPartsID from TableA A group by A.CompanyID ) ,TableBPartsCount as ( select CompanyID, count(ProductID) as #ofTableBProductPartsID from TableB group by CompanyID ) select A.CompanyID, A.#ofTableAProductPartsID, B.#ofTableBProductPartsID from TableBPartsCount B join TableAPartsCount A on A.CompanyID = B.CompanyID
Calculate a column value backwards over a series of previous rows/RECURSIVE/CONNECTED BY
need your help. I guess/hope there is a function for that. I found "CONNECT DBY" and "WITH RECURSIVE AS ..." but it doesn't seem to solve my problem. GIVEN TABLES: Table A +------+------------+----------+ | id | prev_id | date | +------------------------------+ | 1 | | 20200101 | | 23 | 1 | 20200104 | | 34 | 23 | 20200112 | | 41 | 34 | 20200130 | +------------------------------+ Table B +------+-----------+ | ref_id | key | +------------------+ | 41 | abc | +------------------+ (points always to the lates entry in table "A". Update, no history) Join Statement: SELECT id, prev_id, key, date FROM A LEFT OUTER JOIN B ON B.ref_id = A.id GIVEN psql result set: +------+------------+----------+-----------+ | id | prev_id | key | date | +------------------------------+-----------+ | 1 | | | 20200101 | | 23 | 1 | | 20200104 | | 34 | 23 | | 20200112 | | 41 | 34 | abc | 20200130 | +------------------------------+-----------+ DESIRED output: +------+------------+----------+-----------+ | id | prev_id | key | date | +------------------------------+-----------+ | 1 | | abc | 20200101 | | 23 | 1 | abc | 20200104 | | 34 | 23 | abc | 20200112 | | 41 | 34 | abc | 20200130 | +------------------------------+-----------+ The rows of the result set are connected by columns 'id' and 'prev_id'. I want to calculate the "key" column in a reasonable time. Keep in mind, this is a very simplified example. Normally there are a lot of more rows and different keys and id's
I understand that you want to bring the hierarchy of each row in tableb. Here is one approach using a recursive query: with recursive cte as ( select a.id, a.prev_id, a.date, b.key from tablea a inner join tableb b on b.ref_id = a.id union all select a.id, a.prev_id, a.date, c.key from cte c inner join tablea a on a.id = c.prev_id ) select * from cte
MyBatis SELECT query with IF condition
I have a table sample_table like this +-------+-------+-------+-------+-------------+ | pkey1 | pkey2 | mode | type | type_number | +-------+-------+-------+-------+-------------+ | 001 | 01 | light | type1 | 1234 | | 001 | 02 | light | type2 | 2345 | | 002 | 01 | dark | type1 | 3456 | | 002 | 02 | dark | type2 | 4567 | +-------+-------+-------+-------+-------------+ I have a MyBatis SELECT query pseudo-code like this SELECT Master.pkey1, Master.pkey2, Master.mode, Master.type, T1.selectedNumber type_number FROM ( SELECT * from sample_table) as Master left join (select type_number as selectedNumber from sample_table where type='type1') as T1 ON T1.pkey1 = Master.pkey1 left join (select type_number as selectedNumber from sample_table where type='type2') as T2 ON T2.pkey1 = Master.pkey1) Is there a way to select from T1 or T2 based on the value in mode, like SELECT Master.pkey1, Master.pkey2, Master.mode, Master.type, if Master.type='light' T1.selectedNumber type_number if Master.type='dark' T2.selectedNumber type_number My expected result is something like this +-------+-------+-------+-------+-------------+ | pkey1 | pkey2 | mode | type | type_number | +-------+-------+-------+-------+-------------+ | 001 | 01 | light | type1 | 1234 | | 001 | 02 | light | type2 | 1234 | | 002 | 01 | dark | type1 | 4567 | | 002 | 02 | dark | type2 | 4567 | +-------+-------+-------+-------+-------------+ Edit: Added Some extra code and the expected result
How about just using window functions? select s.*, (case when mode = 'light' then max(case when type = 'type1' then type_number end) over (partition by pkey1) else max(case when type = 'type2' then type_number end) over (partition by pkey2) end) from sample_table s;
Comparing two numbers strings and getting out the unique values
Here is a sample table I made to better illustrate my problem: Create Table SampleTable( TableID int, NumberRow nvarchar(500) ) Insert into SampleTable Values(1, '15,21,23,41,44,5,50,59,6,') Insert into SampleTable Values(2, '10,24,29,41,5,50,59,6,73,') Insert into SampleTable Values(3, '10,15,21,24,29,33,41,50,59,60,61,62,66,73,') Insert into SampleTable Values(4, '10,15,21,24,28,33,37,41,44,5,50,6,60,61,62,66,') Insert into SampleTable Values(5, '15,24,33,41,5,6,61,62,66,73,') TableID NumberRow --------------------------------- 1 15,21,23,41,44,5,50,59,6, 2 10,24,29,41,5,50,59,6,73, 3 10,15,21,24,29,33,41,50,59,60,61,62,66,73, 4 10,15,21,24,28,33,37,41,44,5,50,6,60,61,62,66, 5 15,24,33,41,5,6,61,62,66,73, After that I wrote a self join query: Select t1.TableID AS ID1, t2.TableID AS ID2, t1.NumberRow AS Numbers1, t2.NumberRow AS Numbers2 From SampleTable t1 inner join SampleTable t2 on t1.TableID = t2.TableID - 1 Order by t2.TableID asc Which results in: ID1 ID2 Numbers1 Numbers2 ------------------------------------------------------------------------------------- 1 2 15,21,23,41,44,5,50,59,6, 10,24,29,41,5,50,59,6,73, 2 3 10,24,29,41,5,50,59,6,73, 10,15,21,24,29,33,41,50,59,60,61,62,66,73, 3 4 10,15,21,24,29,33,41,50,59,60,61,62,66,73, 10,15,21,24,28,33,37,41,44,5,50,6,60,61,62,66, 4 5 10,15,21,24,28,33,37,41,44,5,50,6,60,61,62,66, 15,24,33,41,5,6,61,62,66,73, Now I want to make two columns that show a string of numbers that are unique to both of the columns (Numbers1 and Numbers2). So far I haven't come up with any solutions. My other approach was to make numbers be in a column instead of a string, but I still couldn't figure out how I could resolve my problem.
Maybe this query can be helpful but I agree with the design considerations about your table select DISTINCT value as NUMBER1 ,'' AS NUMBER2 from ( Select t1.TableID AS ID1, t2.TableID AS ID2, t1.NumberRow AS Numbers1, t2.NumberRow AS Numbers2 From SampleTable t1 inner join SampleTable t2 on t1.TableID = t2.TableID - 1 ) as tmp_tbl CROSS APPLY string_split(tmp_tbl.Numbers1,',') UNION ALL select DISTINCT '', value from ( Select t1.TableID AS ID1, t2.TableID AS ID2, t1.NumberRow AS Numbers1, t2.NumberRow AS Numbers2 From SampleTable t1 inner join SampleTable t2 on t1.TableID = t2.TableID - 1 ) as tmp_tbl CROSS APPLY string_split(tmp_tbl.Numbers1,',') +---------+---------+ | NUMBER1 | NUMBER2 | +---------+---------+ | | | | 10 | | | 15 | | | 21 | | | 23 | | | 24 | | | 28 | | | 29 | | | 33 | | | 37 | | | 41 | | | 44 | | | 5 | | | 50 | | | 59 | | | 6 | | | 60 | | | 61 | | | 62 | | | 66 | | | 73 | | | | | | | 10 | | | 15 | | | 21 | | | 23 | | | 24 | | | 28 | | | 29 | | | 33 | | | 37 | | | 41 | | | 44 | | | 5 | | | 50 | | | 59 | | | 6 | | | 60 | | | 61 | | | 62 | | | 66 | | | 73 | +---------+---------+