I would like to change the column values based on below condition. Appreciate your expert advice on this. I need to prefix the respective column value 'F~' if the column is found in col_lst. Can I achieve this through sql query?
Current Output:
row_id|col_lst|col1|col2|col3|col4
1|col1,col2|1|2|3|4
2|col3,col4|A|B|C|D
3|col2|X|Y|Z|P
Expected Output:
row_id|col_lst|col1|col2|col3|col4
1|col1,col2|F~1|F~2|3|4
2|col3,col4|A|B|F~C|F~D
3|col2|X|F~Y|Z|P
Regards
Mithil
You can use the INSTR function on each column name to determine if it is in the col_lst column.
with test_data(row_id,col_lst,col1,col2,col3,col4) as
( select 1, 'col1,col2', '1', '2', '3', '4' from dual union all
select 2, 'col3,col4', 'A', 'B', 'C', 'D' from dual union all
select 3, 'col2', 'X', 'Y', 'Z', 'P' from dual
)
select row_id
, col_lst
, case when instr(col_lst,'col1')>0 then 'F~' || nvl(col1,' ') else col1 end col1
, case when instr(col_lst,'col2')>0 then 'F~' || nvl(col2,' ') else col2 end col2
, case when instr(col_lst,'col3')>0 then 'F~' || nvl(col3,' ') else col3 end col3
, case when instr(col_lst,'col4')>0 then 'F~' || nvl(col4,' ') else col4 end col4
from test_data;
However this is a case where you should just tell the other team NO. There is nothing added that they cannot determine from the col_lst themselves, and it serves no purpose except output formatting - which the presentation layer should be doing.
Related
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;
I need help with separators in sql. I'm working on DB2 but Oracle is also good.
I need to build query where I've got data in format: aaa.bbb.ccc.ddd#domain.com
where 'aaa', 'bbb', 'ccc', 'ddd' got not constant length. Query should return bbb and ddd. In DB2 I can cut '#domain.com' which takes me really long line. Rest I have no idea how to move. I tried with SUBSTR but nothing has work like it should nad my queries are super long.
I need query not block.
EXAMPLE:
data in column:
John.W.Smith.JWS1#domain.com
Alexia.Nova.Alnov#domain.com
Martha.Heart.Martha2#domain.com
etc.
In general I need to get data from between 1st and 2nd separator . and the one which is in front of #.
I'm sure someone will have some clever REGEX way of doing it, but this is one way to do it.
with test as
( select 'John.W.Smith.JWS1#domain.com' col1 from dual union all
select 'Alexia.Nova.Alnov#domain.com' from dual union all
select 'Martha.Heart.Martha2#domain.com' from dual
)
select col1
, substr( col1, 1, dot_one-1 ) f1
, substr( col1, dot_one+1, dot_two - dot_one -1 ) f2
, no_domain
, substr( no_domain, dot_before_at+1 ) f3
from
(
select col1
,instr( col1, '#', -1 ) at_pos
,instr( col1, '.',1,1) dot_one
,instr( col1, '.',1,2) dot_two
,substr( col1, 1, instr(col1, '#', -1 )-1) no_domain
,instr( substr( col1, 1, instr( col1, '#', -1 ) -1 ) , '.', -1 ) dot_before_at
from test
)
There is a Table (let T) with column (let C) containing only numbers. I wish to retrieve the numbers using select that are only a combination of e.g 1,2,3 like 123123, 111111, 112113, 231213 etc. Please help.
Something that only uses standard SQL and which will work in all RDBMSs:
select c from t
where replace(replace(replace(c, '1', ''), '2', ''), '3', '') = ''
and length(c) > 0
For those that support regex, like Postgres:
select c from t
where c rlike '^[123]+$'
Oracle:
select c from t
where regexp_like(c,'^[123]+$');
Just to point out that a standard SQL solution may not work properly in Oracle.
With a table like this:
create table t(c) as (
select '1233' from dual union all
select '1XX3' from dual union all
select 'XX' from dual union all
select '' from dual
)
The standard approach gives:
SQL> select c from t
2 where replace(replace(replace(c, '1', ''), '2', ''), '3', '') = ''
3 and c <> '';
no rows selected
the reason is in the way Oracle handles empty strings :
SQL> select c,
2 case when replace(replace(replace(c, '1', ''), '2', ''), '3', '') = '' and c <> '' then 'MATCH'
3 else 'NO MATCH'
4 end as checkMatch
5 from t;
C CHECKMAT
---- --------
1233 NO MATCH
1XX3 NO MATCH
XX NO MATCH
NO MATCH
In a simple example:
SQL> select case when '' = '' then 'true' else 'false' end
2 from dual;
CASEW
-----
false
In Oracle, the check should be against NULL:
SQL> select c,
2 case when replace(replace(replace(c, '1', ''), '2', ''), '3', '') is null and c is not null then 'MATCH'
3 else 'NO MATCH'
4 end as checkMatch
5 from t;
C CHECKMAT
---- --------
1233 MATCH
1XX3 NO MATCH
XX NO MATCH
NO MATCH
So an Oracle solution without regexp could be:
SQL> select c from t
2 where replace(replace(replace(c, '1', ''), '2', ''), '3', '') is null
3 and c is not null;
C
----
1233
I have a table like this in SQL Server 2012:
DECLARE #test TABLE (dateField datetime,
col1 varchar(10),
col2 varchar(10)
)
insert into #test
select dateadd(day,-1,getdate()), 'Test A', 'Other A'
union
select dateadd(day,-1,getdate()), 'Test E', 'Other E'
union
select getdate(), 'Test B', 'Other B'
union
select dateadd(day,1,getdate()), 'Test C', 'Other C'
union
select dateadd(day,1,getdate()), 'Test A', 'Other C'
union
select dateadd(day,1,getdate()), 'Test D', 'Other B'
I want to retrieve the data in a specific order.
Order should be:
dateField ASC
Col1 ends with A
Col2 ends with B
If datefield is greater than today's date, then it should switch to col1 check.
If there's no col1 that ends with A, then it should switch to col2 check
If there's no col2 that ends with B, no rows should be returned
Any help would be appreciated. I tried doing case statements in SQL. It didn't work as I expected.
You seem a bit confused about if it is filtered or sorted or a combination of that. This does both.
select
*
from (
SELECT
*
,substring(col1,len(col1),1) [LastCharCol1]
,substring(col2,len(col2),2) [LastCharCol2]
FROM #test
) t
where 1=1
AND (
[LastCharCol1]='A'
OR [LastCharCol2]='B'
)
order by CASE WHEN dateField>CONVERT(DATE,GETDATE()) THEN 1 ELSE 0 END DESC,CASE WHEN [LastCharCol1]='A' THEN 1 ELSE 0 END DESC,CASE WHEN [LastCharCol2]='B' THEN 1 ELSE 0 END DESC
If I understood right, you want to filter records:
select *
from #test
where dateField > getdate() and (col1 like '%A' or col2 like '%B')
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