Type bigint but expression is of type character varying - amazon-redshift

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.

Related

Select row with one column for each row in another select

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);

Postgres | Get all ids after a promo code is used

I'm trying to get all order ids that used a specific promo code (ABC123). However, I want to see all subsequent orders, rather than just all the ids. For example, if we have the following table:
Account_id
order_id
promo_code
1
123
NULL (no promo code used)
2
124
ABC123
3
125
HelloWorld!
2
125
NULL
1
126
ABC123
2
127
HelloWorld!
3
128
ABC123
Ideally, what I want to get is this (ordered by account_id):
Account_id
order_id
promo_code
1
126
ABC123
2
124
ABC123
2
125
NULL
2
127
HelloWorld!
3
128
ABC123
As you can see promo_code = ABC123 is like a placeholder in which all once that ID is found, I want all preceding order_ids.
So far to filer all the account_ids that used this promo_code is:
SELECT account_ids, order_id, promo_code
FROM orders
WHERE account_id IN (SELECT account_id FROM order WHERE promo_code = 'ABC123');
This allows me to get the account_ids that have an order where the desired promo_code was used.
Thanks in advance!
Extract all account_id-s that used 'ABC123' and the smallest corresponding order_number-s (the t CTE) then join these with the table and filter/order the result set.
with t as
(
select distinct on (account_id) account_id, order_id
from the_table where promo_code = 'ABC123'
order by account_id, order_id
)
select the_table.*
from the_table
inner join t on the_table.account_id = t.account_id
where the_table.order_id >= t.order_id -- the subsequent orders
order by the_table.account_id, the_table.order_id;
SQL Fiddle

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

TSQL Grouping problems

I've been given a TSQL table an extract of which is below
Serial Number Code 1 Code 2 Code 3
15872 1242 NULL NULL
15872 NULL 558 222
99955 995 452 NULL
I'd like to group these four fields together to form the following output
Serial Number Code 1 Code 2 Code 3
15872 1242 558 222
99955 995 452 NULL
This looks a simple problem, but I just can't get it right. Any advice would be very much appreciated!
Kind regards,
DJ
You need to use aggregate function in conjunction with Coalesce function , something like this :
select Serial , COALESCE(SUM(code1),0),COALESCE(SUM(code2),0),COALESCE(SUM(code3),0)
from yourTable
group by Serial
This basically replaces NULL as 0 so that you can calculate SUM as intended
Hope this helps !
Oh...misread question twice, haha.
CREATE TABLE #X
(
SerialNumber INT
, Code1 INT
, Code2 INT
, Code3 INT
)
INSERT INTO #X
VALUES
(15872, 1242, NULL, NULL)
, (15872, NULL, 558, 222)
, (99955, 995, 452, NULL)
SELECT
[SerialNumber]
, MAX([Code1]) AS [Code1]
, MAX([Code2]) AS [Code2]
, MAX([Code3]) AS [Code3]
FROM #x
GROUP BY [SerialNumber]
Now, you've not mentioned anything about an aggregate so this assumes that there is only one row that can possibly have the value i.e. this doesn't exist:
Serial Number Code 1 Code 2 Code 3
15872 1242 773 NULL
15872 NULL 558 222

PostgreSQL - dynamic INSERT on column names

I'm looking to dynamically insert a set of columns from one table to another in PostgreSQL. What I think I'd like to do is read in a 'checklist' of column headings (those columns which exist in table 1 - the storage table), and if they exist in the export table (table 2) then insert them in all at once from table 1. Table 2 will be variable in its columns though - once imported ill drop it and import new data to be imported with potentially different column structure. So I need to import it based on the column names.
e.g.
Table 1. - The storage table
ID NAME YEAR LITH_AGE PROV_AGE SIO2 TIO2 CAO MGO COMMENTS
1 John 1998 2000 3000 65 10 5 5 comment1
2 Mark 2005 2444 3444 63 8 2 3 comment2
3 Luke 2001 1000 1500 77 10 2 2 comment3
Table 2. - The export table
ID NAME MG# METHOD SIO2 TIO2 CAO MGO
1 Amy 4 Method1 65 10 5 5
2 Poe 3 Method2 63 8 2 3
3 Ben 2 Method3 77 10 2 2
As you can see the export table may include columns which do not exist in the storage table, so these would be ignored.
I want to insert all of these columns at once, as I've found if I do it individually by column it extends the number of rows each time on the insert (maybe someone can solve this issue instead? Currently I've written a function to check if a column name exists in table 2, if it does, insert it, but as said this extends the rows of the table every time and NULL the rest of the columns).
The INSERT line from my function:
EXECUTE format('INSERT INTO %s (%s) (SELECT %s::%s FROM %s);',_tbl_import, _col,_col,_type,_tbl_export);
As a type of 'code example' for my question:
EXECUTE FORMAT('INSERT INTO table1 (%s) (SELECT (%s) FROM table2)',columns)
where 'columns' would be some variable denoting the columns that exist in the export table that need to go into the storage table. This will be variable as table 2 will be different every time.
This would ideally update Table 1 as:
ID NAME YEAR LITH_AGE PROV_AGE SIO2 TIO2 CAO MGO COMMENTS
1 John 1998 2000 3000 65 10 5 5 comment1
2 Mark 2005 2444 3444 63 8 2 3 comment2
3 Luke 2001 1000 1500 77 10 2 2 comment3
4 Amy NULL NULL NULL 65 10 5 5 NULL
5 Poe NULL NULL NULL 63 8 2 3 NULL
6 Ben NULL NULL NULL 77 10 2 2 NULL
UPDATED answer
As my original answer did not meet requirement came out later but was asked to post an alternative example for information_schema solution so here it is.
I made two versions for solutions:
V1 - is equivalent to already given example using information_schema. But that solution relies on table1 column DEFAULTs. Meaning, if table1 column that does not exist at table2 does not have DEFAULT NULL then it will be filled with whatever the default is.
V2 - is modified to force 'NULL' in case of two table columns mismatch and does not inherit table1 own DEFAULTs
Version1:
CREATE OR REPLACE FUNCTION insert_into_table1_v1()
RETURNS void AS $main$
DECLARE
columns text;
BEGIN
SELECT string_agg(c1.attname, ',')
INTO columns
FROM pg_attribute c1
JOIN pg_attribute c2
ON c1.attrelid = 'public.table1'::regclass
AND c2.attrelid = 'public.table2'::regclass
AND c1.attnum > 0
AND c2.attnum > 0
AND NOT c1.attisdropped
AND NOT c2.attisdropped
AND c1.attname = c2.attname
AND c1.attname <> 'id';
-- Following is the actual result of query above, based on given data examples:
-- -[ RECORD 1 ]----------------------
-- string_agg | name,si02,ti02,cao,mgo
EXECUTE format(
' INSERT INTO table1 ( %1$s )
SELECT %1$s
FROM table2
',
columns
);
END;
$main$ LANGUAGE plpgsql;
Version2:
CREATE OR REPLACE FUNCTION insert_into_table1_v2()
RETURNS void AS $main$
DECLARE
t1_cols text;
t2_cols text;
BEGIN
SELECT string_agg( c1.attname, ',' ),
string_agg( COALESCE( c2.attname, 'NULL' ), ',' )
INTO t1_cols,
t2_cols
FROM pg_attribute c1
LEFT JOIN pg_attribute c2
ON c2.attrelid = 'public.table2'::regclass
AND c2.attnum > 0
AND NOT c2.attisdropped
AND c1.attname = c2.attname
WHERE c1.attrelid = 'public.table1'::regclass
AND c1.attnum > 0
AND NOT c1.attisdropped
AND c1.attname <> 'id';
-- Following is the actual result of query above, based on given data examples:
-- t1_cols | t2_cols
-- --------------------------------------------------------+--------------------------------------------
-- name,year,lith_age,prov_age,si02,ti02,cao,mgo,comments | name,NULL,NULL,NULL,si02,ti02,cao,mgo,NULL
-- (1 row)
EXECUTE format(
' INSERT INTO table1 ( %s )
SELECT %s
FROM table2
',
t1_cols,
t2_cols
);
END;
$main$ LANGUAGE plpgsql;
Also link to documentation about pg_attribute table columns if something is unclear: https://www.postgresql.org/docs/current/static/catalog-pg-attribute.html
Hopefully this helps :)