Display only the columns of two different select statements containing one row? - sql

I have two select statements which both have one row but an fixed number of columns (15).
So far I have tried using intersect but it doesn't seem to do what I want
select 'ABC' as test, 'DEF' as test2, '123' as test3
select 'ABC2' as test, 'DEF' as test2, '124' as test3
Comparing both will display the a string will the differences
The result will the the columns with the different values as a string. In this case:
"'test': 'ABC', 'test3': '123'"

Use a bunch of case expressions to compare each column and output a value if different e.g.
select
case when a.test1 <> b.test1 then 'test1:' + a.test1 else '' end
+ case when a.test2 <> b.test2 then ', test2:' + a.test2 else '' end
+ case when a.test3 <> b.test3 then ', test3:' + a.test3 else '' end
from (
select 'ABC' as test1, 'DEF' as test2, '123' as test3
) a
cross join (
select 'ABC2' as test1, 'DEF' as test2, '124' as test3
) b;
Returns:
Result
test1:ABC, test3:123

Related

How to find values that contains only 0's and any other digit for example 000000001 or 0000010001 or 010101 or 0002 or 02020 or 0090 etc.?

I want to find 'default type values' in SQL that is entered when something like an ID number of company registration number is entered. Some of the values I see is a combination of 0's and another digit from 1-9. Examples I have seen is 00000001, 0000100, 000000002, 000001111, 0000090009, etc. The values vary in length also. Is there a way to find these values without hard coding? The value should contain at least one 0 and one or more of any other digit.
You want all strings that consist of only zero and one other digit. I.e. you want to find '0101', but not '0102'.
In order to do this, remove all zeros first. From the remaining string remove all digits equaling to its first character. This will result in an empty string or a string consisting of additional digits or characters. Only select those resulting in an empty string.
select *
from mytable
where replace(replace(value, '0', ''), substring(replace(value, '0', ''), 1, 1), '') = '';
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=c307bbbf21ceeae619a966e995c3a567
You can use ISNUMERIC() function
SELECT ISNUMERIC(0000004);
This will return 1
SELECT ISNUMERIC('A');
This will return 0
So if you want to select all columns that are numeric only you can use this logic:
select *
from test
where ISNUMERIC(colA) = 1
Here is a small demo
Or you can use TRY_CAST() function:
select *
from test
where try_cast(colA as int) is not null
Alternative solution:
SELECT value
FROM mytable
CROSS JOIN (
SELECT '1' AS num
UNION ALL
SELECT '2'
UNION ALL
SELECT '3'
UNION ALL
SELECT '4'
UNION ALL
SELECT '5'
UNION ALL
SELECT '6'
UNION ALL
SELECT '7'
UNION ALL
SELECT '8'
UNION ALL
SELECT '9'
) n
WHERE REPLACE(REPLACE(value, '0', ''), num, '') = ''
AND REPLACE(value, '0', '') <> ''
AND value LIKE '%0%'

combine distinct row values into a string - sql

I would like to take cells in every row and make them into a string of names... My method already deals with casing.
For example, the table;
'john' | | 'smith' | 'smith'
'john' | 'paul' | | 'smith'
'john' | 'john' | 'john' |
returns:
'john smith'
'john paul smith'
'john'
This would need to run postgreSQL 8.2.15 of postgres so I can't make use of potentially useful functions like CONCAT, and data is in a greenplum db.
Alternatively, a method to directly delete duplicate tokens in a list of strings would let me achieve the larger objective. For example:
'john smith john smith'
'john john smith'
'smith john smith'
returns
'john smith'
'john smith'
'smith john'
The order of the tokens is not important, as long as all the unique values are returned, once only.
Thanks
Normalize your table structure, select distinct name values from that table, create a function to aggregate strings (see, e.g., How to concatenate strings of a string field in a PostgreSQL 'group by' query?), and apply that function. Except for the aggregate function creation, this could all be done in a single statement or view.
I've come up with a solution for you! :)
The following query returns the four columns (which I named col_1,2,3and 4) and removes the duplicates by joining the test_table with itself.
Here is the code:
SELECT t1.col_1, t2.col_2, t3.col_3, t4.col_4
FROM (
SELECT id, col_1
FROM test_table
) AS t1
LEFT JOIN (
SELECT id, col_2
FROM test_table
) as t2
ON (t2.id = t1.id and t2.col_2 <> t1.col_1)
LEFT JOIN (
SELECT id, col_3
FROM test_table
) as t3
ON (t3.id = t1.id and t3.col_3 <> t1.col_1 and t3.col_3 <> t2.col_2)
LEFT JOIN (
SELECT id, col_4
FROM test_table
) as t4
ON (t4.id = t1.id and t4.col_4 <> t1.col_1 and t4.col_4 <> t2.col_2 and t4.col_4 <> t3.col_3);
If you want to obtain the final string, you just substitute the "SELECT" row with this one:
SELECT trim(both ' ' FROM (COALESCE(t1.col_1, '') || ' ' || COALESCE(t2.col_2, '') || ' ' || COALESCE(t3.col_3, '') || ' ' || COALESCE(t4.col_4, '')))
this should work with your version of postgres, according with the docs:
[for the trim and concatenation functions]
https://www.postgresql.org/docs/8.2/static/functions-string.html
//***************************************************
[for the coalesce function]
https://www.postgresql.org/docs/8.2/static/functions-conditional.html
Please let me know if I've been of help :)
P.S. Your question sounds like a bad database design: I would have those columns moved on a table in which you could do this operation by using a group by or something similar. Moreover I would do the string concatenation on a separate script.
But that's my way of doing :)
I would do this by unpivoting the data and then reaggregation:
select id, string_agg(distinct col)
from (select id, col1 from t union all
select id, col2 from t union all
select id, col3 from t union all
select id, col4 from t
) t
where col is not null
group by id;
This assumes that each row has an unique id.
You can also use a giant case:
select concat_ws(',',
col1,
(case when col2 <> col1 then col2 end),
(case when col3 <> col2 and col3 <> col1 then col3 end),
(case when col4 <> col3 and col4 <> col2 and col4 <> col1 then col4 end)
) as newcol
from t;
In ancient versions of Postgres, you can phrase this as:
select trim(leading ',' from
(coalesce(',' || col1, '') ||
(case when col2 <> col1 then ',' || col2 else '' end) ||
(case when col3 <> col2 and col3 <> col1 then ',' || col3 else '' end),
(case when col4 <> col3 and col4 <> col2 and col4 <> col1 then ',' || col4 else '' end)
)
) as newcol
from t;

Oracle NVL with empty string

I have this table where NULL is the NULL value, not the string NULL:
MYCOL
--------
NULL
example
Why does this query not return the NULL row?
select * from example_so where nvl(mycol, '') = '';
'' is again NULL in Oracle, because Oracle doesn't support empty Strings just like Other High Level languages or DBMS..
You need to look for NULL/empty string using IS NULL or IS NOT NULL
No other relational operator work against NULL, though it is syntactically valid. SQLFiddle Demo
It has to be,
select * from example_so where mycol IS NULL
EDIT: As per Docs
Oracle Database currently treats a character value with a length
of zero as null. However, this may not continue to be true in future
releases, and Oracle recommends that you do not treat empty strings
the same as nulls.
Because NULL = NULL is simply unknown. A third state perhaps? It is neither TRUE nor FALSE.
Oracle considers an EMPTY STRING as NULL.
nvl(mycol, '') makes no real sense, as you are making the NULL back to NULL and comparing it again with NULL.
SQL> WITH DATA AS(
2 SELECT 1 val, 'NULL' str FROM dual UNION ALL
3 SELECT 2, NULL str FROM dual UNION ALL
4 SELECT 3, '' str FROM dual UNION ALL
5 SELECT 4, 'some value' str FROM dual)
6 SELECT val, NVL(str, 'THIS IS NULL') FROM data WHERE str IS NULL
7 /
VAL NVL(STR,'THI
---------- ------------
2 THIS IS NULL
3 THIS IS NULL
SQL>
select * from example_so where nvl(mycol, '') = '';
nvl(mycol, '') will be resulted as NULL
and when you compared NULL with empty string it cant be compared
create table t(id varchar2(2));
insert into t values (nvl(null,'')); <------ this will insert NULL
insert into t values (nvl(null,'et'));

CONCATENATE a CASE in Oracle SQL

I need to run a CASE expression on a number of columns, the columns are Boolean, so if it's 0 I need to populate the column with the column name and if it's 1, I ignore the column/value. I then need to concatenate all these columns into one. Is it possible to do this in Oracle SQL?
I've tried this:
Select
||CASE
WHEN COL_A = 0 THEN 'COL_A'
ELSE ''
END||','
||CASE
WHEN COL_B = 0 THEN 'COL_B'
ELSE ''
END||
from ABC.123
Can this even been done? If not this way are there any other ways?
Yes, it will work (if you clean up the syntax). Here's a simple example:
with q as (
select 0 col_a, 1 col_b, 'Rec 1' id from dual
union all
select 1, 0, 'Rec 2' from dual
union all
select 0, 0, 'Rec 3' from dual
)
Select id,
CASE
WHEN COL_A = 0 THEN 'COL_A'
ELSE ''
END||','
||CASE
WHEN COL_B = 0 THEN 'COL_B'
ELSE ''
END "TheString"
from q
Result:
ID TheString
------- -------------------
Rec 1 COL_A,
Rec 2 ,COL_B
Rec 3 COL_A,COL_B

Compatible SQL to test for not null and not empty strings

I want to have compatible SQL for both Oracle database and Microsoft SQL server.
I want a compatible SQL expression that will return true for not null and not empty strings.
If I use:
column <> ''
it will work on Microsoft SQL server but not on Oracle database (as '' is null for Oracle)
If I use:
len(column) > 0
it will work on Microsoft SQL server but not on Oracle database (since it uses length() )
NULLIF is available on both Oracle (doc) and SQL Server (doc). This expression should work:
NULLIF(column, '') IS NOT NULL
In both servers, if column is NULL, then the output of NULLIF will just pass the NULL value through. On SQL Server, '' = '', so the output of NULLIF will be NULL. On Oracle, '' is already NULL, so it gets passed through.
This is my test on SQL Server 2008 R2 Express:
WITH SampleData AS
(SELECT 1 AS col1, NULL AS col2
UNION ALL
SELECT 2, ''
UNION ALL
SELECT 3, 'hello')
SELECT *
FROM SampleData
WHERE NULLIF(col2, '') IS NOT NULL;
And this is my test case on Oracle 10g XE:
WITH SampleData AS
(SELECT 1 AS col1, NULL AS col2 FROM DUAL
UNION ALL
SELECT 2, '' FROM DUAL
UNION ALL
SELECT 3, 'hello' FROM DUAL)
SELECT *
FROM SampleData
WHERE NULLIF(col2, '') IS NOT NULL;
Both return 3 as expected.
How about
CASE WHEN column = '' THEN NULL ELSE column END IS NOT NULL
I think the key here is to differentiate between the case when the empty string is equivalent to NULL and when it isn't:
WHERE CASE WHEN '' = '' THEN -- e.g., SQL Server this is true
CASE WHEN col <> '' AND col IS NOT NULL THEN 'Y'
ELSE 'N'
END
WHEN COALESCE(col,NULL) IS NOT NULL THEN 'Y' -- Not SS, e.g., Oracle
ELSE 'N'
END = 'Y';
If the first case is true then empty string is not the same as null, and we have to test for both string being not null and string not being the empty string. Otherwise, our task is easier because empty string and null evaluate the same.
A try to shorten #DCookie's answer. I like his ( '' = '' ) test.
CASE WHEN ( '' = '' ) THEN ( column <> '' )
ELSE ( column = column )
END
Sadly, the above will not work. The next works in SQL-Server. I can't test in Oracle now:
CASE WHEN '' = '' THEN CASE WHEN column <> '' THEN 1 ELSE NULL END
ELSE CASE WHEN column = column THEN 1 ELSE NULL END
END
which can be written also as:
( '' = '' AND column <> '' )
OR ( '' IS NULL AND column = column )