Unpivot PostgreSQL large number of columns? - arrays

I am trying to unpivot a large dataset, with 250 columns. There is a very good documented solution here unpivot and PostgreSQL.
However, it inputs the column names manually. I'm looking to do something like..
extract all column names into an array
pass the array through unnest
OR,
extract all column names into an array
loop the array by indexing through
using column name values as an input in the unnest
Apologies for being noob, New to SQL!
This dataset is good enough for purposes:
CREATE TEMP TABLE foo (id int, a text, b text, c text);
INSERT INTO foo VALUES (1, 'ant', 'cat', 'chimp'), (2, 'grape', 'mint', 'basil');
SELECT id,
unnest(array['a', 'b', 'c']) AS colname,
unnest(array[a, b, c]) AS thing
-- I would like something like.. unnest(array[column_names]) AS thing
-- where column_names = [a,b,c.. so on]
FROM foo
ORDER BY id;
Expected outcome:
id | colname | thing
1 | a | ant
1 | b | cat
1 | c | chimp
2 | a | grape
2 | b | mint
2 | c | basil

Use JSONB functions, example:
select id, key as colname, value as thing
from foo t
cross join jsonb_each_text(to_jsonb(t)- 'id')
id | colname | thing
----+---------+-------
1 | a | ant
1 | b | cat
1 | c | chimp
2 | a | grape
2 | b | mint
2 | c | basil
(6 rows)

Related

Create 1 array with 2 fields from 2 csv fields in BigQuery

I am currently trying to work through this and I'm unsure as to how to proceed. I have the below data
ID
name
value
One
a,b,c
10,20,30
I would like to turn it into
| ID | properties.name | properties.value |
|:---- |:------: | -----: |
| One | a | 10 |
| | b | 20 |
| | c | 30 |
The below query looked like it was working but instead of having an array it created a nested record with 2 array fields.
SELECT ID
name
, value
, array (
select as struct
split(name, ',') as name
, split(value, ',') as value
) as properties
FROM `orders`
Consider below approach
select id, array(
select as struct name, value
from unnest(split(name)) name with offset
join unnest(split(value)) value with offset
using(offset)
) as properties
from `orders`
if applied to sample data in your question - output is

How to find and count unique values across columns?

I'm using Snowflake and I'm hoping someone can help me understand how to count the number of unique names across columns for each row and overlook null values. Here is a sample of the data. So you can see below I'm looking to count the number of distinct values across the variables Name 1, Name 2, name 3, Name 4.
ID | Type | Name 1 | Name 2 | Name 3 | Name 4 | Expected result
1 | animal | cat | Dog | null | Dog | 2
2 | animal | fish | cat | cat | cat | 2
3 | animal | fish | cat | dog | rat | 4
You could use a unpivot approach:
SELECT ID, Type, COUNT(DISTINCT Name) AS cnt
FROM
(
SELECT ID, Type, Name1 AS Name FROM yourTable UNION ALL
SELECT ID, Type, Name2 FROM yourTable UNION ALL
SELECT ID, Type, Name3 FROM yourTable UNION ALL
SELECT ID, Type, Name4 FROM yourTable
) t
GROUP BY ID, Type;
Demo
This approach works by unpivoting the name data to a format where one record has just one ID and one name. Then, we aggregate and take the distinct count. The COUNT() function works well here, because by default it ignores NULL values, which is the behavior you want.

Searching Multiple Columns with Multiple Values SQL

I know it is posible to serach multiple columns with one value.
I would like to serach 3-4 columns for 4 maybe 5 values
I want to check if any of my choosen columns have a certain value in them.
Example
Column 1 | Column 2 | Column 3 | Column 4
| | |
Hello | | | = True
| | |
| Goodbye | | = True
| | Hello | Goodbye = True
| | |
| Hello | | = True
| | |
| | Goodbye | = True
In the example I would like SQL to pull the data from all of the lines that have Hello or Goodbye even both in some cases.
Is there a way to do what I want?
There is one more way...
SELECT *
FROM TableName
WHERE 'Value1' IN (Col1,Col2,Col3...) OR 'Val2' in (Col1,Col2,Col3...) OR ...
If it's only 3 or 4 columns, the simplest solution would be something like this:
SELECT *
FROM TableName
WHERE Column1 IN('Hello', 'Goodbye')
OR Column2 IN('Hello', 'Goodbye')
OR Column3 IN('Hello', 'Goodbye')
OR Column4 IN('Hello', 'Goodbye')
Forgot to follow with my solution: I needed to join 2 tables and search across the columns. They ****ed up and made the id of t1 a varchar, smh, and some of them had nulls so we needed to check for them lest our results were ****ed (this is why the selected answer wouldn't work for me). You don't need the aliases but if you were going deeper it helps keep things straight.
Use "+" operator to add columns to a WHERE, check for nulls, and caste if you need too.
SELECT *
FROM Table1 AS t1
LEFT OUTER JOIN Table2 AS t2
ON t1.id = t2.id
WHERE( ISNULL(CONVERT(VARCHAR,t1.id),'') + ISNULL(t1.name,'') + ISNULL(t1.desc,'') + ISNULL(t2.company,'')) LIKE '%xbox%'

Database Views to simulate normalised tables from a single denormalised one

We have a report store with a denormalised flat table that stores identical data to a multi-table model in a different database.
Flat table (example):
| col 1 | col 2 | col 3 | timestamp |
|-------|-------|-------|-----------|
| val1 | val2 | val3 | 1/1/1990 |
| val1 | val9 | val3 | 1/1/1990 |
In multiple tables:
| id1 | id2 | timestamp |
|-----|-----|-----------|
| 001 | 111 | 1/1/1990 |
| 001 | 112 | 1/1/1990 |
| id1 | col 1 | col 3 |
|-----|-------|-------|
| 001 | val1 | val3 |
| id2 | col 2 |
|-----|-------|
| 111 | val2 |
| 112 | val9 |
There are several old reporting queries that we would like to port over to the new flat table without having to rewrite them all up front - there are many of them and they are complex.
Is there a way of writing Views that can simulate a set of relational tables from the single flat table, so that the old reporting queries work without modification?
HereI create dynamical IDs. You could also initialy make that table with fix keys, and always when adding or removing a row in the flattable do the same with the key here. Otherwise instead of Groub by use the OVER statement.
CREATE VIEW multitabkey AS
SELECT ROW_NUMBER() as key, col1, col3
FROM flattable
Group by col1, col3
WARNING: those keys are not persistent: if you delete the first row, all others get their id one smaler than before. You have dynamic IDs, but they are consistnet.
If you have a translation for your Keys you can use them as following:
CREATE VIEW multitabone AS
SELECT f.timestamp
FROM flattable as f
JOIN multitabkey as m ON m.col1 = f.col1 AND m.col3 = f.col3
Group by col1, col3
I assumed col1 , col2 are together a natural key.
As mentioned, this is a workaround, your DB is not in 3rd normalform what can cause inconsistency.

Unpivot SQL each row in SQL table to key-value pairs with group IDs

Running SQL Server 2012, I have a table in the following format:
ENC_ID | Name | ED_YN | Seq
-------------------------------------
1234 | John | Y | 1
1234 | Sally | N | 2
2345 | Chris | N | 1
2345 | Sally | N | 2
I would like to unpivot this into a entity-attribute-value list (if that's the right terminology - I am thinking of them as key-value pairs grouped by IDs), with the following format:
ENC_ID | Seq | Key | Value
--------------------------------------
1234 | 1 | Name | John
1234 | 1 | ED_YN | Y
1234 | 2 | Name | Sally
1234 | 2 | ED_YN | N
2345 | 1 | Name | Chris
2345 | 1 | ED_YN | N
2345 | 2 | Name | Sally
2345 | 2 | ED_YN | N
I have seen various answers to this using UNION or UNPIVOT, but these solutions tend to be long and must be closely customized to the table. I'm looking for a solution that can be reused without a great deal of rewriting as this pattern solves a problem I expect to run into frequently (ingesting data from star-schema into Tableau via extracts, where I don't necessarily know the number of value columns).
The closest thing I've found to solve this is this question/answer but I haven't had success altering the solution to add ENC_ID and Seq to each row in the result table.
Thanks.
I will use Cross Apply with table valued Constructor to do this unpivoting
select ENC_ID, Seq, Key, Value
from yourtable
cross apply
(values ('Name',Name),
('ED_YN',ED_YN)) CS (Key,Value)
You can try below query. This uses classic UNPIVOT syntax.
Since I am unsure about your column types I have casted both of them as varchar(100). You can increase length from 100.
Working sql fiddle demo link :
select enc_id,seq, k [key],v [value] from
(select enc_id,seq,cast(name as varchar(100)) as name, cast(ed_yn as varchar(100)) as ed_yn from r)s
UNPIVOT
( v for k in ([name],[ed_yn])
)up

Resources