How do I select non null unequal values across columns? - sql

I would like to select records where values across 5 columns, if not null, are unequal. Any number of columns can be non null.
schema:
given table
**Schema (SQLite v3.30)**
CREATE TABLE test (
id INT,
col1 text,
col2 text,
col3 text,
col4 text,
col5 text
);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (1, 'EA', 'EA', null, null, null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (2, 'EA', 'MT', null, null, null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (3, null, 'EA', null, 'KG', null);
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (4, null, null, 'KG', 'MT', 'AB');
INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (5, null, null, 'EA', 'MT', 'EA');
---
**Query #1**
SELECT * FROM test;
| id | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 1 | EA | EA | | | |
| 2 | EA | MT | | | |
| 3 | | EA | | KG | |
| 4 | | | KG | MT | AB |
| 5 | | | EA | MT | EA |
---
Desired output
| id | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 2 | EA | MT | | | |
| 3 | | EA | | KG | |
| 4 | | | KG | MT | AB |
| 5 | | | EA | MT | EA |
EDIT: To clarify, id=5 is included in the output since not all values are the same. When I stated values across all columns are unequal, I meant if if any value is distinct from the rest of the non null values. To state it differently, I require records which have at least 1 non null value different from the other non null value.

Hmmm . . . this is tricky. Assuming that the empty values are NULL and no values are blank and you want all distinct values, you can do:
select t.*
from test t
where (col1 is null or col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
(col2 is null or col2 not in (coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
(col3 is null or col3 not in (coalesce(col4, ''), coalesce(col5, ''))) and
(col4 is null or col4 not in (coalesce(col5, '')))
EDIT:
If you just want more than one distinct value, then:
select t.*
from test t
where col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
col2 not in (coalesce(col1, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
col3 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col4, ''), coalesce(col5, '')) or
col4 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col3, ''), coalesce(col5, ''))
Here is a db<>fiddle.
Note: This does not return rows with only one value which technically do not meet your specifications.

You can aggregate on the union of each id with 1 of the columns and set the condition in the having clause:
with cte as (
select id from (
select id, col1 col from test union all
select id, col2 from test union all
select id, col3 from test union all
select id, col4 from test union all
select id, col5 from test
)
where col is not null
group by id
having count(distinct col) > 1
)
select * from test where id in cte
See the demo.
Results:
> id | col1 | col2 | col3 | col4 | col5
> -: | :--- | :--- | :--- | :--- | :---
> 2 | EA | MT | null | null | null
> 3 | null | EA | null | KG | null
> 4 | null | null | KG | MT | AB
> 5 | null | null | EA | MT | EA

Related

Create View with reverse Row values SQL

I have data like
name| col1 | col2 | col3 | col4 | col4 | col5 |
rv | rv1 | rv2 | rv3 | rv4 | | |
sgh | sgh1 | sgh2 | | | | |
vik | vik1 | vik2 | vik3 | vik4 |vik5 |vik6 |
shv | shv1 | shv2 | shv3 | shv4 |shv5 | |
Table Name: emp_data
to create View to get DATA like
name| col1 | col2 | col3 | col4 | col4 | col5 |
rv | rv4 | rv3 | rv2 | rv1 | | |
sgh | sgh2 | sgh1 | | | | |
vik | vik6 | vik5 | vik4 | vik3 |vik2 |vik1 |
shv | shv5 | shv4 | shv3 | shv2 |shv1 | |
MySql 8 supports LATERAL, this way you can sort values by positions and conditionally aggregate them back.
with tbl(name, col1, col2, col3 ,col4 ,col5 , col6) as
(
select 'rv ','rv1 ','rv2 ','rv3 ','rv4 ',null,null union all
select 'sgh','sgh1','sgh2', null,null,null,null union all
select 'vik','vik1','vik2','vik3','vik4','vik5','vik6' union all
select 'shv','shv1','shv2','shv3','shv4','shv5', null
)
select tbl.name, t.*
from tbl
, lateral (
select
max(case n when 1 then val end) col1,
max(case n when 2 then val end) col2,
max(case n when 3 then val end) col3,
max(case n when 4 then val end) col4,
max(case n when 5 then val end) col5,
max(case n when 6 then val end) col6
from (
select row_number() over( order by n) n, val
from (
select case when col1 is null then 99 else 6 end n, col1 val union all
select case when col2 is null then 99 else 5 end n, col2 val union all
select case when col3 is null then 99 else 4 end n, col3 val union all
select case when col4 is null then 99 else 3 end n, col4 val union all
select case when col5 is null then 99 else 2 end n, col5 val union all
select case when col6 is null then 99 else 1 end n, col6 val
) t
) t
) t
db<>fidle

sql copying duplicates

I'm trying to fill 'Col4' null values with the values above using 'Col1' and 'Col3'. Here is a brief explanation of the columns:
Col1 - User Entry date
Col2 - Calendar date
Col3 - Difference between the dates in Col1
Col4 - Entry amount
What the data currently looks like:
| Col1 | Col2 | Col3 | Col4
| 2016-01-01 | 2016-01-01 | 3 | $10
| null | 2016-01-02 | null | null
| null | 2016-01-03 | null | null
| 2016-01-04 | 2016-01-04 | 1 | $2
| 2016-01-05 | 2016-01-05 | 2 | $7
| null | 2016-01-06 | null | null
| 2016-01-07 | 2016-01-07 | 3 | $5
| null | 2016-01-08 | null | null
| null | 2016-01-09 | null | null
Expected Results:
| Col1 | Col2 | Col3 | Col4
| 2016-01-01 | 2016-01-01 | 3 | $10
| null | 2016-01-02 | null | $10
| null | 2016-01-03 | null | $10
| 2016-01-04 | 2016-01-04 | 1 | $2
| 2016-01-05 | 2016-01-05 | 2 | $7
| null | 2016-01-06 | null | $7
| 2016-01-07 | 2016-01-07 | 3 | $5
| null | 2016-01-08 | null | $5
| null | 2016-01-09 | null | $5
The formula works by counting the number in Col3 and then copying the corresponding amount in Col4 to the rows below. Col3 defines how many rows below (including its own row).
I'm currently using Sybase. I don't have any ideas on how I can do this. Any help would be appreciated thanks.
Note: this is a sample of data and the dates go from 2000 - 2016
In SQL Server By given sample data we can achieve the above result Set by using CTE
Sample Data :
declarE #Table1 TABLE
(Col1 varchar(10), Col2 varchar(10), Col3 varchar(4), Col4 varchar(4))
;
INSERT INTO #Table1
(Col1, Col2, Col3, Col4)
VALUES
('2016-01-01', '2016-01-01', '3', '$10'),
(NULL, '2016-01-02', NULL, NULL),
(NULL, '2016-01-03', NULL, NULL),
('2016-01-04', '2016-01-04', '1', '$2'),
('2016-01-05', '2016-01-05', '2', '$7'),
(NULL, '2016-01-06', NULL, NULL),
('2016-01-07', '2016-01-07', '3', '$5'),
(NULL, '2016-01-08', NULL, NULL),
(NULL, '2016-01-09', NULL, NULL)
;
Script :
WITH cte
AS (SELECT T1.Col1,
T1.Col2,
T1.Col3,
Col4 = COALESCE(T1.Col4, (SELECT TOP 1 Col4
FROM #Table1 T2
WHERE T2.Col2 < T1.Col2
AND Col4 IS NOT NULL
ORDER BY Col2 DESC))
FROM #Table1 T1)
UPDATE T
SET
T.Col4 = C.Col4
FROM #Table1 T
INNER JOIN cte C
ON T.col2 = C.col2
WHERE T.col1 IS NULL
OR T.col2 IS NULL
OR T.col3 IS NULL
Select * from #Table1

Concatenate values from multiple columns in Oracle

I'm working with an oracle database and what I basically need to concatenate in one column, values from multiple columns for every row.
Something like this:
col1 col2 col3 col4 col5
____________________________________
1 A B C D
2 A B C
3 C A
4 D A C
col1 col2
____________
1 A,B,C,D
2 A,B,C
3 C,A
4 D,A,C
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test (col1, col2, col3, col4, col5 ) AS
SELECT 1, 'A', 'B', 'C', 'D' FROM DUAL
UNION ALL SELECT 2, 'A', 'B', 'C', NULL FROM DUAL
UNION ALL SELECT 3, 'C', 'A', NULL, NULL FROM DUAL
UNION ALL SELECT 4, 'D', 'A', 'C', NULL FROM DUAL
UNION ALL SELECT 5, NULL, NULL, NULL, NULL FROM DUAL
UNION ALL SELECT 6, NULL, NULL, NULL, 'A' FROM DUAL
UNION ALL SELECT 7, 'B', NULL, NULL, 'A' FROM DUAL
UNION ALL SELECT 8, NULL, 'C', NULL, 'A' FROM DUAL;
Query 1:
If there are no NULL values between other values (it will introduce multiple commas in rows 7 & 8):
SELECT col1,
TRIM( ',' FROM col2||','||col3||','||col4||','||col5 ) AS col2
FROM test
Results:
| COL1 | COL2 |
|------|---------|
| 1 | A,B,C,D |
| 2 | A,B,C |
| 3 | C,A |
| 4 | D,A,C |
| 5 | (null) |
| 6 | A |
| 7 | B,,,A |
| 8 | C,,A |
The last two queries will work for all examples:
Query 2:
SELECT col1,
TRIM( ',' FROM col2 || NVL2( col3, ','||col3, NULL ) || NVL2( col4, ','||col4, NULL ) || NVL2( col5, ','||col5, NULL ) ) AS col2
FROM test
Results:
| COL1 | COL2 |
|------|---------|
| 1 | A,B,C,D |
| 2 | A,B,C |
| 3 | C,A |
| 4 | D,A,C |
| 5 | (null) |
| 6 | A |
| 7 | B,A |
| 8 | C,A |
Query 3:
SELECT col1,
REGEXP_REPLACE( col2||','||col3||','||col4||','||col5, '(^|,),+|,+($)', '\1' ) AS col2
FROM test
Results:
| COL1 | COL2 |
|------|---------|
| 1 | A,B,C,D |
| 2 | A,B,C |
| 3 | C,A, |
| 4 | D,A,C |
| 5 | (null) |
| 6 | A |
| 7 | B,A |
| 8 | C,A |
Use below query
select col1,rtrim( col2||','||col3||','||col4||','||col5,' ,') as col2 from table_name
there's probably a better way of handling the trailing comma, but this should work
SELECT col1,
col2 || decode(col3,'','',',') || col3 || decode(col4,'','',',') || col4 || decode(col5,'','',',')|| col5 as "col2"
FROM table
Use concatenation ||
Select Col1|| ',' ||Col2|| ',' ||Col2|| ',' ||Col3|| ',' || Col4 As OneCol
From Table;

Issue in joining 2 datasets

I have two datasets like below:
1:
+---------------------------+
| Id | Col1 | Col2 | Col3 |
+---------------------------+
| 1 | abc | 0 | 01/01/2010 |
| 2 | def | 10 | 10/10/2011 |
+---------------------------+
2:
+-------------------------------------------+
| Id | Col4 | Col5 | Col6 |
+-------------------------------------------+
| 1 | abc | 0 | 01/01/2010 |
| 5 | xyz | 12 | 5/6/2013 |
+-------------------------------------------+
Now I want to combine both these into a single dataset which shows something like this:
+----------------------------------------------------------------------+
| ID | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+----------------------------------------------------------------------+
| 1 | abc | 0 | 01/01/2010 | abc | 0 | 01/01/2010 |
| 2 | def | 10 | 10/10/2011 | null | null | null |
| 5 | null | null | null | xyz | 12 | 5/6/2013 |
+----------------------------------------------------------------------+
The issue is not all ids in dataset 1 are in dataset 2 and vice versa. What i need as all data from datasets1 and 2 and only the common from 1 and 2 with 2 transposed with 1 as shown above. I have used pipe as a separator.
An inputs are highly appreciated. i tried everything like full outer join, inner join , CTE etc - nothing is working.
CREATE TABLE #TEMP1 (ID INT, Col1 VARCHAR(100), Col2 INT, Col3 DATETIME)
CREATE TABLE #TEMP2 (ID INT, Col4 VARCHAR(100), Col5 INT, Col6 DATETIME)
INSERT INTO #TEMP1 VALUES (1,'abc',0,'1/1/2010')
INSERT INTO #TEMP1 VALUES (1,'def',0,'1/1/2010')
INSERT INTO #TEMP2 VALUES (1,'abc',0,'1/1/2010')
INSERT INTO #TEMP2 VALUES (1,'def',0,'1/1/2010')
SELECT DISTINCT A.ID,A.Col1,A.Col2,A.Col3,B.Col4,B.Col5,B.Col6
FROM #TEMP1 A
FULL OUTER JOIN #TEMP2 B ON A.ID = B.ID
Thanks.
Try using below SQL :
select t1.Id , Col1 , Col2 , Col3 , Col4 , Col5 , Col6
from temp1 t1 left join temp2 t2
on t1.Id=t2.Id
union
select t2.Id , Col1 , Col2 , Col3 , Col4 , Col5 , Col6
from temp1 t1 right join temp2 t2
on t1.Id=t2.Id
Also, i tried on fiddle for you :
http://sqlfiddle.com/#!2/d60a1e/5

how to remove null values in a table sql

I have a table (TestTable) as follows
PK | COL1 | COL2 | COL3 | COL4 | COL5
1 | 1 | NULL | NULL | NULL | NULL
2 | NULL | 43 | 1.5 | 7.8 | NULL
3 | NULL | NULL | NULL | NULL | 1
4 | 1 | NULL | NULL | NULL | NULL
5 | NULL | 48 | 10.5 | 17.8 | NULL
6 | NULL | NULL | NULL | NULL | 1
I would like a result as follows
PK | COL1 | COL2 | COL3 | COL4 | COL5
1 | 1 | 43 | 1.5 | 7.8 | 1
2 | 1 | 48 | 10.5 | 17.8 | 1
I have tried the following
Select
[COL1],
[COL2],
[COL3],
[COL4],
(select top 1
[COL5] from TestTable
where [COL5] is not null and PK <= t1.pk
order by PK DESC) as [COL5]
FROM TestTable as t1
Where
[COL1] IS NOT NULL AND
[COL2] IS NOT NULL AND
[COL3] IS NOT NULL AND
[COL4] IS NOT NULL
The script works however I get empty result set. Any thoughts?
It looks like you have a value in col1 followed by a set of rows that should be combined into one row until the next value in col1.
If so, you can do this by assigning to each row a count -- the number of non-null values in col1 on or before the row. This can then be used for aggregation.
You don't mention the database, so I'll do this using a correlated subquery:
select row_number() over (order by max(pk)) as pk,
max(col1) as col1,
max(col2) as col2,
max(col3) as col3,
max(col4) as col4,
max(col5) as col5
from (select t.*,
(select count(t2.col1)
from testtable t2
where t2.pk <= t.pk
) as grpid
from testtable t
) t
group by grpid;
You don't have any rows in TestTable where
[COL1] IS NOT NULL AND
[COL2] IS NOT NULL AND
[COL3] IS NOT NULL AND
[COL4] IS NOT NULL