How to group options within a dimension? - group-by

I have a dimension called 'group':
Within 'group' dimension, there are drop down options for 'group A', 'group B', 'group C', 'group D', 'group E' and 'group E-1'.
I would like to groupby(or group) drop down options 'group E' and 'group E-1' can call it 'group X'. So in my drop down I get 'group X' as an option.
How can I do this?

Something like this should work for you.
dimension: group {
type: string
sql: CASE
WHEN ${TABLE}.group IN ('Group E','Group E-1') THEN 'Group X'
ELSE ${TABLE}.group
END ;;
}

Related

How to group by multiple columns with OR statement transitively?

I want to select rows from a table grouped by multiple columns connected by OR. (Not the usual AND when you use multiple group by clauses.)
In contrast to other questions already asked it should also be transitive, meaning when by common value in one of the columns row A connects to B, and row B connects to row C, then also row A should be connected to row C (making A, B, C one group).
The setup:
CREATE TABLE test.tab1 (
rowid STRING,
col1 STRING,
col2 STRING,
col3 STRING
);
INSERT INTO test.tab1
(rowid, col1, col2, col3)
VALUES
( '1', 'A', 'Q', 'green'),
( '2', 'B', 'R', 'blue'),
( '3', 'B', 'S', 'red'),
( '4', 'C', 'T', 'purple'),
( '5', 'D', 'U', 'orange'),
( '6', 'E', 'R', 'black'),
( '7', 'F', 'U', 'brown'),
( '8', 'F', 'V', 'pink'),
( '9', 'G', 'W', 'white'),
('10', 'H', 'R', 'cyan'),
('11', 'A', 'Y', 'grey'),
('12', 'I', 'Z', 'azul'),
('13', 'H', 'X', 'magenta');
rowid
col1
col2
col3
1
A
Q
green
2
B
R
blue
3
B
S
red
4
C
T
purple
5
D
U
orange
6
E
R
black
7
F
U
brown
8
F
V
pink
9
G
W
white
10
H
R
cyan
11
A
Y
grey
12
I
Z
azul
13
H
X
magenta
The query should select all rows grouped by col1 OR col2, meaning when one of them is equal to another value of that column in a different row, rows get connected together. The expected result would be (for simplicity grouped columns are concatenated strings):
INSERT INTO test.result
(rowid, col1, col2, col3)
VALUES
( '1,11', 'A', 'Q,Y', 'green,grey'),
( '2,3,6,10,13', 'B,E,H', 'R,S,X', 'blue,red,black,cyan,magenta'),
( '4', 'C', 'T', 'purple'),
( '5,7,8', 'D,F', 'U,V', 'orange,brown,pink'),
( '9', 'G', 'W', 'white'),
('12', 'I', 'Z', 'azul');
rowid
col1
col2
col3
1,11
A
Q,Y
green,grey
2,3,6,10,13
B,E,H
R,S,X
blue,red,black,cyan,magenta
4
C
T
purple
5,7,8
D,F
U,V
orange,brown,pink
9
G
W
white
12
I
Z
azul
The try adapted from a similar question:
-- This is not transitive and does not work as desired.
-- For example it does not connect row 2 blue (col2=R) with row 13 magenta (col1=H),
-- even though they are both connected to row 10 cyan (col2=R, col1=H).
SELECT t1.col1,
STRING_AGG(t2.col3, ',') AS col3
FROM test.tab1 AS t1 INNER JOIN test.tab1 AS t2
ON t2.rowid = t1.rowid OR t2.col2 = t1.col2
GROUP BY t1.col1
HAVING COUNT(DISTINCT t1.rowid) > 1 OR COUNT(t2.rowid) = 1;
I am looking for solutions that work in BigQuery, but an answer for PostgreSQL would probably help a lot already. I have prepared a DB fiddle as the syntax is really similar and I believe an answer could easily be adapted.

How can I use a CASE in a SELECT in BigQuery if a field exactly matches one or more text strings (words)?

What I want to do is to do something (THEN) when another field contains either 'Click video' or 'Click button'
SELECT
CASE
WHEN field IS EXACTLY 'Click video' or 'Click button' THEN do something to another field
END
The simpler approach I see
SELECT
CASE
WHEN field in ('Click video', 'Click button')
THEN do something to another field
END
Try IF or CASE:
WITH Numbers AS
(SELECT 10 as A, 20 as B UNION ALL
SELECT 50, 30 UNION ALL
SELECT 60, 60)
SELECT
A, B,
IF( A<B, 'true', 'false') as result
FROM Numbers
WITH Numbers AS
(SELECT 90 as A, 2 as B UNION ALL
SELECT 50, 8 UNION ALL
SELECT 60, 6 UNION ALL
SELECT 50, 10)
SELECT A, B,
CASE A
WHEN 90 THEN 'red'
WHEN 50 THEN 'blue'
ELSE 'green'
END
AS result
FROM Numbers
WITH Numbers AS
(SELECT 90 as A, 2 as B UNION ALL
SELECT 50, 6 UNION ALL
SELECT 20, 10)
SELECT A, B,
CASE
WHEN A > 60 THEN 'red'
WHEN A > 30 THEN 'blue'
ELSE 'green'
END
AS result
FROM Numbers

How to get array of descendants from adjacency lists?

I have the following table and data
CREATE TABLE relationships (a TEXT, b TEXT);
CREATE TABLE nodes(n TEXT);
INSERT INTO relationships(a, b) VALUES
('1', '2'),
('1', '3'),
('1', '4'),
('1', '5'),
('2', '6'),
('2', '7'),
('2', '8'),
('3', '9');
INSERT INTO nodes(n) VALUES ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8'), ('9'), ('10');
I want to output
n | children
1 | ['2', '3', '4', '5', '6', '7', '8', '9']
2 | ['6', '7', '8', '9']
3 | ['9']
4 | []
5 | []
6 | []
7 | []
8 | []
9 | []
10 | []
I am trying to use WITH RECURSIVE but is stuck on how to pass parameter into CTE
WITH RECURSIVE traverse(n) AS (
SELECT *
FROM relationships
WHERE a = n --- not sure how to pass data to here
UNION ALL
...
)
WITH basic_cte AS (
SELECT a1.n as n,
(SELECT COALESCE(json_agg(temp), '[]')
FROM (
(SELECT * FROM traverse(a1.a))
) as temp
) as children
FROM nodes as a1
)
SELECT *
FROM basic_cte;
To get a list of the children of all nodes, you need a left join to the nodes table
with recursive rels as (
select a,b, a as root
from relationships
union all
select c.*, r.root
from relationships c
join rels r on r.b = c.a
)
select n.n, array_agg(r.b) filter (where r.b is not null)
from nodes n
left join rels r on r.root = n.n
group by n.n
order by n.n;
Note: This ignores any empty children. You can add a left join like in #a_horse_with_no_name's answer to get that functionality.
You can't really pass a parameter into the CTE unless you veer off into stored procedures and whatnot. The CTE is a single table that needs to contain all the rows you might want to use from it.
Assuming a fairly nice graph (no duplicate edges, no cycles), code like the following ought to do what you're looking for.
The base case for the recursive query gets all level-1 descendants (the children) for all nodes which could possibly be parents.
The recursive step walks through the 2nd level, 3rd level, etc down the tree.
Once we have all parent-descendant tuples we can aggregate the data as desired.
WITH RECURSIVE descendants(parent, child) AS (
SELECT * FROM relationships
UNION
SELECT d.parent, r.b
FROM descendants d JOIN relationships r ON d.child=r.a
)
SELECT parent AS n, array_agg(child) AS children
FROM descendants
GROUP BY parent

How to "group" column results with same property in PostgreSQL?

I have a couple of tables, the main table has a property called "id", and the thing table has a property called "id_main". A main item may have more than one things. A thing may only have one main. How do i do to get an array with every thing of a main? My query works, but returns as many things it has copies of main properties, each one with a different thing relationed. This is my query:
SELECT
m.id
, x.color
, t.volume
, t.age
FROM main m
LEFT JOIN extra x
ON x.id = m.id
LEFT JOIN thing t
ON t.id = m.id
WHERE m.id = 1234;
It's returning :
{id: 1234, color: 'red', volume: '8', age: '10'}
{id: 1234, color: 'red', volume: '3', age: '25'}
{id: 1234, color: 'red', volume: '19', age: '152'}
And I would like to get:
{id: 1234, color: 'red', things:[{volume:'8', age:'10'}, {volume:'3', age:'25'}, {volume:'19', age:'152'}]}
Or the closest possible. Is there an easy way to do it?
If you are flexible about having 'volume' and 'age' split in 2 arrays, your select could look like this:
SELECT
m.id
, x.color
, array_agg(t.volume) as t_volume
, array_agg(t.age) as t_age
FROM main m
LEFT JOIN extra x
ON x.id = m.id
LEFT JOIN thing t
ON t.id = m.id
WHERE m.id = 1234
GROUP BY m.id, x.color;

T-SQL select starting from value condition

In SQL server 2008, I have below table.
Thanks
create table test1 ([Number] int, Item varchar(10))
insert into test1 values (20 , 'Item 1'),(30 , 'Item 2'),(60 , 'Item 3'),(23 , 'Item 4'),(10 , 'Item 5'),(76 , 'Item 6'),(44 , 'Item 7'),(99 , 'Item 8'),(10 , 'Item 9'),(22 , 'Item 10'),(77 , 'Item 11'),(10 , 'Item 12')
Without a specific primary key, there is no inherent order to the data in the table, e.g. imagine each record as a sheet of paper dumped in a basket (in no particular order).
select a.*--, b.pvt
from test1 a
inner join (select MIN(1*substring(item,6,10)) pvt from test1 where number=10) b
on 1*substring(a.item,6,10) >= b.pvt
order by 1*substring(a.item,6,10)
I have made the following assumptions:
The order is by the Item number, where
Item number is always the 6th character onwards in the column "Item"
If the assumptions are wrong, then you can still use a similar technique, which is to find the pivotal record and join to it using >=