dynamic selection in SQL aggregate function - sql

Imagine I have a column with row data A, B, and C. When aggregating the column, I want B to show up if any row contains B, else C, else A.
Is this possible? I'm using vertica but would be curious to hear solutions for other data stores.
+------+-------+
| Col1 | Col 2 |
+------+-------+
| A | X |
| B | X |
| C | X |
+------+-------+
SELECT ???(Col1), Col2
FROM my_two_column_table
GROUP BY Col2
expected result: one row - B, X

Something like this could work:
SELECT COALESCE( MAX(t2.value), MAX(t3.value), MAX(t4.value) )
FROM my_table t1
LEFT OUTER JOIN my_table t2 ON t2.value = 'B'
LEFT OUTER JOIN my_table t3 ON t3.value = 'C'
LEFT OUTER JOIN my_table t4 ON t4.value = 'A'
WHERE t1.value in ( 'A', 'B', 'C' )
The t1 table can also be replaced by dual or whatever dummy table with at least one row you have.

Related

SQL Join instead of UNION

I have the following tables:
Table T1
--------------------------
ZID | NAME
------------------------
1 | Test
Table C1
--------------------------
ZID | VALUE1
------------------------
1 | A
1 | B
Table S1
--------------------------
ZID | VALUE2
------------------------
1 | C
1 | D
I would like a select query to fetch the values below
----------------------------------
ZID | NAME | VALUE1 | VALUE2
----------------------------------
1 | Test | A | null
1 | Test | B | null
1 | Test | null | C
1 | Test | null | D
I am able to achieve the above by using a UNION by faking a column in each select as below.
SELECT
ZID,
NAME,
VALUE1,
NULL AS VALUE2
FROM
T1
LEFT JOIN C1 ON (
T1.ZID = C1.ZID
)
UNION ALL
(
SELECT
ZID,
NAME,
NULL AS VALUE1,
VALUE2
FROM
T1
LEFT JOIN S1 ON (
T1.ZID = S1.ZID
)
);
Would it be possible to retrieve data as above in a single select using JOINS? I have tried using left join and however, I end up with a Cartesian product of data in the results.
You could use:
select t1.*, c1.value1, s1.value2
from c1 full join
s1
on false join
t1
on t1.id in (c1.id, s1.id)
A full join on false is a lot like union all.
Query will be something like:
SELECT ZID, NAME, VALUE1, VALUE2
FROM T1, C1, S1;
Union will give you more rows. Join will give you more columns. If you want to join them to get one set of rows with all columns, you need to specify which rows go together. For example, if you do not specify which C1 row goes with which S1 row, it matches each to all of them, and gives the product you do not want.
Define the relationship in the on clause, and it will do what you want.
You need the UNION to add rows. You can put the join on the outside of the UNION to avoid having to do it twice:
SELECT
ZID,
NAME,
VALUE1,
NULL AS VALUE2
FROM
T1
LEFT JOIN (
SELECT ZID, VALUE1, NULL AS VALUE2
FROM C1
UNION ALL
SELECT ZID, NULL AS VALUE1, VALUE2
FROM S1
) Merged ON T1.ZID = Merged.ZID

Join tables with same keys, second table has multiple values for key and rows of second table must have same column value

I have two tables with shared key and I'm trying to join them to filter data based on few conditions
tbl1
id | OutPutValue |
1 | 2019 |
2 | 2018 |
tbl2
object_id | status | type |
1 | 22 | a |
1 | 22 | c |
1 | 33 | b |
2 | 33 | c |
2 | 33 | c |
2 | 33 | c |
What I'm trying to get is : it must select all 'OutPutValue' from tbl1 where, in tbl2 column 'type' should be c, and column 'status' must have same value for all rows i.e. 33. Note that Primary key (id) of tbl1 is foreign key (object_id) in tbl2.
Select column from tbl1 if, All rows in tbl2 (id of tbl1 have multiple rows (based on object_id) in tbl2) have same status value i.e. 33 and Type should be 'c'.
OutPutValue | Type | status |
2018 | c | 33 |
I have tried with following solution, but it's not returning desired output :
SELECT a.OutPutValue FROM tbl1 a JOIN tbl2 b ON a.id = b.object_id WHERE b.Type =c
GROUP BY a.OutPutValue, b.status HAVING b.STATUS IN(33)
You can try using correlated subquery
DEMO
select distinct OutPutValue,type, status
from t2 a inner join t1 b on a.object_id=b.id
where type='c' and not exists
(select 1 from t2 a1 where a.object_id=a1.object_id and status<>33 and type='c')
OUTPUT:
OutPutValue type status
2018 c 33
Another solution could be the following :
SELECT T1.id, T1.outputvalue FROM tbl1 T1
JOIN (
SELECT tbl2.*, MAX(type), MAX(status)
FROM tbl2
GROUP BY object_id
HAVING
MIN(status) = MAX(status) AND
MIN(type) = MAX(type)
) T2 ON T1.id = T2.object_id
WHERE T2.type = 'c'
EDIT: I have updated my query to match a particular case which make it quite similar to another answer.
FIND A DEMO HERE
Try a join combined with an aggregation:
SELECT
t1.OutPutValue,
MAX(t2.type) AS type,
MAX(t2.status) AS status
FROM tbl1 t1
INNER JOIN tbl2 t2
ON t1.id = t2.object_id
GROUP BY
t1.id,
t1.OutPutValue
HAVING
MIN(t2.status) = MAX(t2.status) AND
MAX(t2.status) = 33 AND
MIN(t2.type) = MAX(t2.type) AND
MAX(t2.type) = 'c';

get name of tuples that match an entire column in another table

I have to select every name from table1 where there's tuples that match every type from table2 without grouping or aggregate functions.
table1 table2
name|type type|info
a | 1 1 | .
a | 2 2 | ..
a | 3 3 | ...
b | 1
b | 2
b | 3
c | 2
From here, it should output
name|
a |
b |
edit:
ended up doing something like
SELECT distinct outside.name
FROM table1 outside
WHERE '' NOT IN
[ (SELECT *
FROM table1 t
WHERE t.name=outside.name)
RIGHT OUTER JOIN
table2 ]
Second select makes a table with empty values for names that don't have a type in table2. So if '' isn't in the second select that means it has a tuple for every type in table2. I think
Here is one method:
select t1.name
from table1 t1
where exists (select 1 from table2 t2 where t2.type = t1.type)
group by t1.name
having count(distinct t1.type) = (select count(distinct t2.type) from table2);
This filters t1 down to the matches in t2. It then counts the number that match.
This uses count(distinct), which allows duplicates in the respective tables. If there are no duplicates, then just use count().

Merging two tables into new table by ID and date

Let' say I have two tables:
table 1:
col a | col b | col c
1 | 62215 | 21
1 | 62015 | 22
2 | 62215 | 23
2 | 51315 | 24
and table 2:
col a | col b| col f
1 | 62015| z
1 | 62215| x
2 | 51315| y
2 | 62215| t
Where neither column a and column b are unique on their own, but the pairs (col a, col b) are all unique. How would I go about merging these two tables, to produce a
Table 3:
col a | col b| col c | col f
I want to combine these tables together, into one big table. So the new table has the values from column a and b from both tables, along with the columns unique to either table 1 or two.
I'm sure this is an extremely simple problem using MERGE or UNION but I don't use SQL at all, so I don't know how it would look like.
Thank you.
You can use a SELECT statement when inserting into a table. What I would do here is write a select statement that pulls all of the columns you need first. You will have to do a full outer join (simulated by a union of left and right joins) because some pairs may exist in one table but not the other. The select would look like this:
SELECT t1.colA, t1.colB, t1.colC, t2.colF
FROM tab1 t1
LEFT JOIN tab2 t2 ON t2.colA = t1.colA AND t2.colB = t1.colB
UNION
SELECT t1.colA, t1.colB, t1.colC, t2.colF
FROM tab1 t1
RIGHT JOIN tab2 t2 ON t2.colA = t1.colA AND t2.colB = t1.colB;
Then, to insert into table 3:
INSERT INTO tab3 (mySelect);
Here is an SQL Fiddle example.
Note that for the pairs that exist in one table and not the other, you will get NULL values. For example, if a row exists in table 1 and not table 2, colF will be null in table 3.
I'm not sure if I understand the data. Are you saying that colA and colB are unique across both tables? do you want to join or union?
As a union:
Select `col a`,`col b`, `col c`, null
from `table 1`
union
Select `col a`,`col b`, null, `col f`
from `table 2`
As a join:
Select `table 1`.`col a`,`table 1`.`col b`,`table 1`.`col c`,`table 2`.`col f`
from `table 1` join `table2`
on `table 1`.`col a` = `table 1`.`col a`
on `table 1`.`col b` = `table 1`.`col b`
to insert into a table put
insert into `table 3`
in front of it.
I hope this helps.
The union would produce 1 record for every record in each of table 1 and 2. A join will combine the data if col a and col b are the same in both tables. I think the latter is what you want. I didn't use a union all because that might create duplicates.

Need to retrieve rows from table where the following condition was not satisfied column A = column B and column B = column A

I hope I am able to explain what I am looking for. I have a table as follows:
ID | Column A| Column B
1 | 1234 | 9876
2 | 1234 | 8765
3 | 9876 | 1234
4 | 2345 | 3456
5 | 3456 | 2345
The rule is that For Every value of Column A = Value A and Column B = Value B, I need to have a row where Column A = Value B and Column B = Value A.
Here, I have ID = 1, 3, 4 and 5 satisfying this condition.
I need to pull ID = 2 as this was not satisfying the rule.
Will this query work for the above condition:
select * from TABLE1 T1 where T1.ID not in (select ID from TABLE1
where T1.Column A = Column B and T1.Column B = Column A)
Is there a better way to write this query?
The following should work:
SELECT * FROM TABLE1 T1
WHERE NOT EXISTS (SELECT 1 FROM TABLE1 T2
WHERE T1.ColumnA = T2.ColumnB AND
T1.ColumnB = T2.ColumnA)
Use an outer self-join filtering out matches:
select a.*
from table1 a
left join table1 b on a.columna = b.columnb
and a.columnb = b.columna
where b.columnb is null
select
a.*
from
Table1 a
join
Table1 b on
a.ColumnA = b.ColumnB and
a.ColumnB = b.ColumnA