Select row with one column for each row in another select - postgresql

An existing query returns the following table:
UserID
Sector
Value
1
1
111
1
2
122
1
3
133
2
2
222
2
3
233
3
1
311
But I would like to "reformat" it in the following way:
UserID
Sector 1
Sector 2
Sector 3
1
111
122
122
2
222
233
3
311
The maximum number of sectors is variable. Since i am new to SQL I am not sure weather this would be something DB Type Specific, so a solution which works for PostgreSQL is appreciated.
If this is something which should not be done in the database, it is also okay. I am still figuring out what to do in the database and what not.
Title is not good, I know. Please make some recommendation if you have an more precise one.

Unfortunately you cannot have dynamic number of columns.
Here is the SQL for the sample data you've provided. You must have tablefunc extension installed.
SELECT *
FROM crosstab(
'select userid, sector, value
from user_sector
order by 1,2')
AS ct(userid int, sector1 int, sector2 int,sector3 int);

Related

How to replace values in a column in a table by condition in PostgreSQL?

I have a table named "building" in PostgreSQL. It has several columns and millions of rows. Each row has a unique id. It looks like
id tags height building:levels area
1 apartment 58 m 17 109
2 apartment null null 111
3 shed 7 2 75sqm
4 greenhouse 6m 3 159
5 industrial 16 2;4 105
6 commercial 27 8 474
And I have another csv file with cleaned data for column height and building:levels. The csv looks like:
id height building:levels
1 58 17
3 7 2
4 6 3
5 16 4
6 27 8
I want to join the csv file back to the table on the server, and the final outcome might look like this:
id tags height building:levels area
1 apartment 58 17 109
2 apartment null null 111
3 shed 7 2 75sqm
4 greenhouse 6 3 159
5 industrial 16 4 105
6 commercial 27 8 474
I want to replace the values in height and building:levels where the id are the same in the table and the csv file. I've tried to import data from csv but it didn't replace the values, only adding new rows. How can I achieve this?
You can import the csv file data in a temporary table first :
CREATE TEMPORARY TABLE IF NOT EXISTS building_temp LIKE building ;
COPY building_temp (id, height, "building:levels") FROM your_csv_file.csv WITH options_list ;
See the manual for building the options_list.
and then update the building table from that temporary table
UPDATE building AS b
SET height = bt.height
, "building:levels" = bt."building:levels"
FROM building_temp AS bt
WHERE b.id = bt.id

Type bigint but expression is of type character varying

I'm hoping someone can lend a hand with this:
Trying to insert one row per order_id in a database that is running in RedShift, and sometimes subscription_id contains more than 1 value. This creates duplicate rows, so I figured I would LISTAGG. This is the line:
LISTAGG(DISTINCT CAST(script.subscription_id AS VARCHAR), ',') AS subscription_id
The subscription_id column is an int8 and after giving me the character varying error, I tried to CAST; but for some reason I cannot do it. Does LISTAGG do not support this type of nested CAST? If not, is there a wasy to actually achieve this?
ORIGINAL:
order_id subscription_id
1 123
2 124
3 125
1 126
2 127
IDEAL:
order_id subscription_id
1 123,126
2 124,127
3 125
Both columns are of int8.

Is there a way to update a table using random values in each row in a table with multiple primary keys?

We have a databade in postgresql ver 11.7 on the pgAdmin4 which has a table with 3 primary keys .We want to update each row with a random value between 1 and 10 .
We have found the desirable elements but we need a way to update only 1 row each time
the conditions are as follow :
1)The subjects much be in a specific semester which can be found in the table called "Courses"
2)then we must find the amkas of students who are registered ( register_status = 'approved')
and we need to upade the table called "Register" with random exam_grades with those conditions assuming the exam_grade is null
Update "Register" SET exam_grade = (SELECT floor(random() * 10 + 1)::int) WHERE course_code IN
(SELECT DISTINCT course_code FROM "Course" WHERE typical_year = 2 AND typical_season = 'spring' ) AND register_status = 'approved' AND exam_grade is null ;
Just that .Somehow we need the update to just be used on only one row and then just use a for loop to take it one by one.If there is any other information i should include ,please tell me
So the tables are as follows
Register:
amka(PK) serial_number(PK) course_code(PK) exam_grade final_grade lab_grade register_status
19 5 ΕΝΕ 501 null null null proposed
13 15 ΤΗΛ 417 2 2 null fail
13 15 ΤΗΛ 411 10 8.4 null pass
47 22 ΜΠΔ 433 6 null 9 approved
:
Course:
course_code(PK) typical_year typical_season units ects weight obligatory
ΑΓΓ 201 2 winter 2 4 1 true
ΜΑΘ 201 1 winter 4 6 1.5 true
ΜΑΘ 208 1 winter 3 5 1.5 false
The results that i want are
mka(PK) serial_number(PK) course_code(PK) exam_grade final_grade lab_grade register_status
19 5 ΕΝΕ 501 random null null approved
13 15 ΤΗΛ 417 random 2 null approved
13 15 ΤΗΛ 411 random 8.4 null approved
47 22 ΜΠΔ 433 random null 9 approved
new random in each row
but i only get 1 number which fills all of them
i hope with this edit things became clearer

TSQL, Pivot rows into single columns

Before, I had to solve something similar:
Here was my pivot and flatten for another solution:
I want to do the same thing on the example below but it is slightly different because there are no ranks.
In my previous example, the table looked like this:
LocationID Code Rank
1 123 1
1 124 2
1 138 3
2 999 1
2 888 2
2 938 3
And I was able to use this function to properly get my rows in a single column.
-- Check if tables exist, delete if they do so that you can start fresh.
IF OBJECT_ID('tempdb.dbo.#tbl_Location_Taxonomy_Pivot_Table', 'U') IS NOT NULL
DROP TABLE #tbl_Location_Taxonomy_Pivot_Table;
IF OBJECT_ID('tbl_Location_Taxonomy_NPPES_Flattened', 'U') IS NOT NULL
DROP TABLE tbl_Location_Taxonomy_NPPES_Flattened;
-- Pivot the original table so that you have
SELECT *
INTO #tbl_Location_Taxonomy_Pivot_Table
FROM [MOAD].[dbo].[tbl_Location_Taxonomy_NPPES] tax
PIVOT (MAX(tax.tbl_lkp_Taxonomy_Seq)
FOR tax.Taxonomy_Rank in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15])) AS pvt
-- ORDER BY Location_ID
-- Flatten the tables.
SELECT Location_ID
,max(piv.[1]) as Tax_Seq_1
,max(piv.[2]) as Tax_Seq_2
,max(piv.[3]) as Tax_Seq_3
,max(piv.[4]) as Tax_Seq_4
,max(piv.[5]) as Tax_Seq_5
,max(piv.[6]) as Tax_Seq_6
,max(piv.[7]) as Tax_Seq_7
,max(piv.[8]) as Tax_Seq_8
,max(piv.[9]) as Tax_Seq_9
,max(piv.[10]) as Tax_Seq_10
,max(piv.[11]) as Tax_Seq_11
,max(piv.[12]) as Tax_Seq_12
,max(piv.[13]) as Tax_Seq_13
,max(piv.[14]) as Tax_Seq_14
,max(piv.[15]) as Tax_Seq_15
-- JOIN HERE
INTO tbl_Location_Taxonomy_NPPES_Flattened
FROM #tbl_Location_Taxonomy_Pivot_Table piv
GROUP BY Location_ID
So, then here is the data I would like to work with in this example.
LocationID Foreign Key
2 2
2 670
2 2902
2 5389
3 3
3 722
3 2905
3 5561
So I have some data that is formatted like this:
I have used pivot on data like this before--But the difference was it had a rank also. Is there a way to get my foreign keys to show up in this format using a pivot?
locationID FK1 FK2 FK3 FK4
2 2 670 2902 5389
3 3 722 2905 5561
Another way I'm looking to solve this is like this:
Another way I could look at doing this is I have the values in:
this form as well:
LocationID Address_Seq
2 670, 5389, 2902, 2,
3 722, 5561, 2905, 3
etc
is there anyway I can get this to be the same?
ID Col1 Col2 Col3 Col4
2 670 5389, 2902, 2
This, adding a rank column and reversing the orders, should gives you what you require:
SELECT locationid, [4] col1, [3] col2, [2] col3, [1] col4
FROM
(
SELECT locationid, foreignkey,rank from #Pivot_Table ----- temp table with a rank column
) x
PIVOT (MAX(x.foreignkey)
FOR x.rank in ([4],[3],[2],[1]) ) pvt

PostgreSQL UPDATE FROM

Apologies if this has been answered elsewhere, I'm afraid I need a little more clarification/brushing up on the UPDATE FROM clause in PostgreSQL.
Basically I have a temporary table with some intermediary computed stuff that I want to use to update the main table. This temporary table includes two foreign keys and a score, such as:
score fk_offer fk_searchprofile
65 1764 12345
...
I tested the rows to be updated with a select (the table temp_offerids_with_score contains the offers that need to be updated):
SELECT s.pkid, tmp.fk_offer, s.fk_category, tmp.score, tmp.fk_searchprofile
FROM
temp_weighted_scores_offers AS tmp
INNER JOIN sc_sp_o_c_score AS s
ON tmp.fk_offer = s.fk_offer
WHERE
tmp.fk_offer IN (SELECT fk_offer FROM temp_offerids_with_score)
AND
s.fk_category = 1
AND s.fk_searchprofile = 12345;
This correctly returns the expected number of rows (in this case 10):
pkid fk_offer fk_category score fk_searchprofile
1 47 1 78 12345
2 137 1 64 12345
3 247 1 50 12345
...
However, if I use the same in an UPDATE FROM:
UPDATE sc_sp_o_c_score
SET score = tmp.score
FROM
temp_weighted_scores_offers AS tmp
INNER JOIN sc_sp_o_c_score AS s
ON tmp.fk_offer = s.fk_offer
WHERE
tmp.fk_offer IN (SELECT fk_offer FROM temp_offerids_with_score)
AND
s.fk_category = 1
AND s.fk_searchprofile = 12345;
the whole table, over 32000 rows, gets updated with the same (wrong, of course) score overall.
pkid fk_offer fk_searchprofile fk_category score
1 47 12345 1 104
2 137 12345 1 104
3 247 12345 1 104
What am I missing?
Thanks, Julian
EDIT: just in case this could be of any help - for the record, I'm migrating things from SQL Server here, where this is in fact a valid construct.
You are using the table to be updated also as a self-join (through reference in the FROM clause). Take that out and you should be good:
UPDATE sc_sp_o_c_score
SET score = tmp.score
FROM temp_weighted_scores_offers AS tmp
WHERE tmp.fk_offer = fk_offer
AND tmp.fk_offer IN (SELECT fk_offer FROM temp_offerids_with_score)
AND fk_category = 1
AND fk_searchprofile = 12345;