SQL query to group a column and ignore null values - sql

I have a table like:
Col1 Col2 Col3 Col4
1 a
1 b
1 c
2 e
2 f
2 g
I need to write a query which will have the output like this
Col1 Col2 Col3 Col4
1 a b c
2 e f g
I am using oracle 10g

If you only have one value per column, then you might be able to use an aggregate function:
select
col1,
max(col2) col2,
max(col3) col3,
max(col4) col4
from yourtable
group by col1
See SQL Fiddle with Demo
The result is:
| COL1 | COL2 | COL3 | COL4 |
-----------------------------
| 1 | b | a | c |
| 2 | e | f | g |

Related

sql table comparisons - postgres

I have two tables with some columns being the same:
TABLE A
| Col1 | Col2 | Col3 |
+------+------+------+
| 1 | aa | ccc |
| 2 | null | ccc |
| null | bb | null |
TABLE B
|Col1 | Col2 | Col3| Col4 |
+------+-------+-----+------+
| 1 | aa | ccc | aaaa |
| 2 | null | ccc | cccc |
| null | bb | null | sss |
| 4 | bb | null | ddd |
I'd like to return the following:
|Col1 | Col2 | Col3| Col4 |
+------+-------+-----+------+
| 4 | bb | null | ddd |
How do I check what rows from table B are in table A and also return Col4 (from table B) where they match in the query.
I was using EXCEPT which worked great but now I need to have the outputs of Col4 in the returned query results.
Thanks.
Something like this?
SELECT Col1, Col2, Col3, Col4
FROM TableB
WHERE NOT EXISTS (
SELECT 1
FROM TableA
WHERE TableA.Col1 IS NOT DISTINCT FROM TableB.Col1
AND TableA.Col2 IS NOT DISTINCT FROM TableB.Col2
AND TableA.Col3 IS NOT DISTINCT FROM TableB.Col3
)
(Using IS NOT DISTINCT FROM to say that columns with null are equal to each other.)
The answer to your question is very easy: none of the rows from table 'A' are in table 'B'.
Those are separate tables and they have separate rows.
Now, if you want to find 'a row in table B, that has similar values in columns as a specific row in table A, you may do following:
select a.*,
case when b.ctid is null then 'I AM A VERY SAD PENGUIN AND ROW IN B WAS NOT FOUND :('
else b.col4 end as col4
from table_a a
left join table_b b on
((a.col1 = b.col1 or (a.col1 is null and b.col1 is null)) and
(a.col2 = b.col2 or (a.col2 is null and b.col2 is null)) and
(a.col3 = b.col3 or (a.col3 is null and b.col3 is null))
)
I assume that by 'similar' you would mean "if null appears in columns in both tables, the rows are still similar.
Notice the last insert into table_b i added - you are not guaranteed to find unique values of col4!:
dbfiddle, modified version of VBoka's answer
If you have no duplicates within the b table, then the following handles NULL values rather elegantly:
select col1, col2, col3, max(col4)
from ((select coll, col2, col3, null as col4, 'a' as which
from a
) union all
(select coll, col2, col3, col4, 'b' as which
from b
)
) b
group by col1, col2, col3
having min(which) = 'b';

Join two table and shows with null values

I have two tables:
Table 1
Col | Col2
--------+---------
AA | CC
Table 2
Col | Col2
--------+---------
BB | CC
Result I need
Col1 | Col2 | Col4
--------+----------+---------
AA | CC | null
null | CC | BB
I can't find any relation between two tables so, i would do :
select col as col1, col2, null as col4
from table1 t1
union all
select null, col2, col
from table2 t2;

BigQuery: Union two different tables which are based on federated Google Spreadsheet

I have two different Google Spreadsheet:
One with 4 columns
+------+------+------+------+
| Col1 | Col2 | Col5 | Col6 |
+------+------+------+------+
| ID1 | A | B | C |
| ID2 | D | E | F |
+------+------+------+------+
One with the 4 columns of the previous file, and 2 more columns
+------+------+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+------+------+------+------+------+------+
| ID3 | G | H | J | K | L |
| ID4 | M | N | O | P | Q |
+------+------+------+------+------+------+
I configured them as Federated source in Google BigQuery, now I need to create a view that will join data of both tables.
Both tables have Col1 column, which contains an ID, this ID is unique across alla the tables, does not contain replicated data.
The resulting table I'm looking for is the following one:
+------+------+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+------+------+------+------+------+------+
| ID1 | A | NULL | NULL | B | C |
| ID2 | D | NULL | NULL | E | F |
| ID3 | G | H | J | K | L |
| ID4 | M | N | O | P | Q |
+------+------+------+------+------+------+
For the columns that the first file does not have, I'm expecting a NULL value.
I'm using standardSQL, here is a statement you can use to generate a sample data:
#standardsQL
WITH table1 AS (
SELECT "A" as Col1, "B" as Col2, "C" AS Col3
UNION ALL
SELECT "D" as Col1, "E" as Col2, "F" AS Col3
),
table2 AS (
SELECT "G" as Col1, "H" as Col2, "J" AS Col3, "K" AS Col4, "L" AS Col5
UNION ALL
SELECT "M" as Col1, "N" as Col2, "O" AS Col3, "P" AS Col4, "Q" AS Col5
)
A simple UNION ALL is not working because tables have different columns
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
Error: Queries in UNION ALL have mismatched column count; query 1 has 3 columns, query 2 has 5 columns at [17:1]
And wildcard operator is not a suitable way because Federated sources does not support that
SELECT * FROM `table*`
Error: External tables cannot be queried through prefix
Of course this is a sample data, with only 3-5 columns, the real tables have 20-40 columns. So an example where I need to explicitly SELECT field by field it is not a considerable way.
Is there a working way to join this two tables?
You can pass the rows through a UDF to handle the case where column names aren't aligned by position or there are different numbers of them between tables. Here is an example:
CREATE TEMP FUNCTION CoerceRow(json_row STRING)
RETURNS STRUCT<Col1 STRING, Col2 STRING, Col3 STRING, Col4 STRING, Col5 STRING>
LANGUAGE js AS """
return JSON.parse(json_row);
""";
WITH table1 AS (
SELECT "A" as Col5, "B" as Col3, "C" AS Col2
UNION ALL
SELECT "D" as Col5, "E" as Col3, "F" AS Col2
),
table2 AS (
SELECT "G" as Col1, "H" as Col2, "J" AS Col3, "K" AS Col4, "L" AS Col5
UNION ALL
SELECT "M" as Col1, "N" as Col2, "O" AS Col3, "P" AS Col4, "Q" AS Col5
)
SELECT CoerceRow(json_row).*
FROM (
SELECT TO_JSON_STRING(t1) AS json_row
FROM table1 AS t1
UNION ALL
SELECT TO_JSON_STRING(t2) AS json_row
FROM table2 AS t2
);
+------+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 | Col5 |
+------+------+------+------+------+
| NULL | C | B | NULL | A |
| NULL | F | E | NULL | D |
| G | H | J | K | L |
| M | N | O | P | Q |
+------+------+------+------+------+
Note that the CoerceRow function needs to declare the explicit row type that you want in the output. Outside of that, the columns in the tables being unioned are just matched by name.
Is there a working way to join this two tables?
#standardsQL
SELECT *, NULL AS Col5, NULL AS Col6 FROM table1
UNION ALL
SELECT * FROM table2
Yo can check this using your example
#standardsQL
WITH table1 AS (
SELECT "ID1" AS Col1, "A" AS Col2, "B" AS Col3, "C" AS Col4
UNION ALL
SELECT "ID2", "D", "E", "F"
),
table2 AS (
SELECT "ID3" Col1, "G" AS Col2, "H" AS Col3, "J" AS Col4, "K" AS Col5, "L" AS Col6
UNION ALL
SELECT "ID4", "M", "N", "O", "P", "Q"
)
SELECT *, NULL AS Col5, NULL AS Col6 FROM table1
UNION ALL
SELECT * FROM table2

Split Microsoft SQL Row

Assume I have data like so:
+------+------+------+------+
| Col1 | Col2 | Col3 | Col4 |
+------+------+------+------+
| a | b | x | y |
+------+------+------+------+
I wish to split it after a certain column to achieve something like this:
+------+------+
| Col1 | Col2 |
+------+------+
| a | b |
| x | y |
+------+------+
What would be the easiest way to achieve this? I am currently forced to do this in an old MS Access database with a connection to the SQL server. Thoughts?
Use union all:
select col1, col2
from t
union all
select col3, col4
from t;
Both databases support union all. Both will take the column names from the first subquery.
Try this,
select col1 as Col1 , col2 as Col2
from t
union all
select col3 as Col1, col4 as Col2
from t;

Trying to write a query that will display duplicates results as null

I have a table that looks like the first example.
I'm trying to write a MSSQL2012 statement that that will display results like the second example.
Basically I want null values instead of duplicate values in columns 1 and 2. This is for readability purposes during reporting.
This seems like it should be possible, but I'm drawing a blank. No amount of joins or unions I've written has rendered the results I need.
| Col1 | Col2 | Col3 |
+------+------+------+
| 1 | 2 | 4 |
| 1 | 2 | 5 |
| 1 | 3 | 6 |
| 1 | 3 | 7 |
+------+------+------+
| Col1 | Col2 | Col3 |
+------+------+------+
| 1 | 2 | 4 |
| Null | null | 5 |
| null | 3 | 6 |
| null | null | 7 |
+------+------+------+
I would do this with no subqueries at all:
select (case when row_number() over (partition by col1 order by col2, col3) = 1
then col1
end) as col1,
(case when row_number() over (partition by col2 order by col3) = 1
then col2
end) as col2,
col3
from t
order by t.col1, t.col2, t.col3;
Note that the order by at the end of the query is very important. The result set that you want depends critically on the ordering of the rows. Without the order by, the result set could be in any order. So, the query might look like it works, and then suddenly fail one day or on a slightly different set of data.
Using a common table expression with row_number():
;with cte as (
select *
, rn_1 = row_number() over (partition by col1 order by col2, col3)
, rn_2 = row_number() over (partition by col1, col2 order by col3)
from t
)
select
col1 = case when rn_1 > 1 then null else col1 end
, col2 = case when rn_2 > 1 then null else col2 end
, col3
from cte
without the cte
select
col1 = case when rn_1 > 1 then null else col1 end
, col2 = case when rn_2 > 1 then null else col2 end
, col3
from (
select *
, rn_1 = row_number() over (partition by col1 order by col2, col3)
, rn_2 = row_number() over (partition by col1, col2 order by col3)
from t
) sub
rextester demo: http://rextester.com/UYA17142
returns:
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
| 1 | 2 | 4 |
| NULL | NULL | 5 |
| NULL | 3 | 6 |
| NULL | NULL | 7 |
+------+------+------+