selection based on certain condition - sql

select col1, col2, col3 from tab1
rownum col1 col2 col3
1 1 10 A
2 1 15 B
3 1 0 A
4 1 0 C
5 2 0 B
6 3 20 C
7 3 0 D
8 4 10 B
9 5 0 A
10 5 0 B
Output required is
col1 col2 col3
1 10 A
1 15 B
2 0 B
3 20 C
4 10 B
5 0 A
5 0 B
col1 and col2 are my lookup/joining columns columns, if col2 is having "non zero" data then I need to ignore/filter record with 0 (in above example I need to filter record rownum 3 4 and 7) If col2 is not having any data other than "non zero" in that case only select record with 0 (in above example col1 with value 1 and 5).
I m trying to write sql for this. Hope I have mentioned requirement clearly, please let me know if you need anything more from my side. Seem to have gone blank in this case.
Database - Oracle 10g

SELECT col1,
col2,
col3
FROM (SELECT col1,
col2,
col3,
sum(col2) OVER (PARTITION BY col1) sum_col2
FROM tab1)
WHERE ( ( sum_col2 <> 0
AND col2 <> 0)
OR sum_col2 = 0)
If col2 can be negative and the requirement is that the sum of col2 has "non-zero" data then the above is OK, however, if it is the requirement that any col2 value has "non-zero" data then it should be changed to:
SELECT col1,
col2,
col3
FROM (SELECT col1,
col2,
col3,
sum(abs(col2)) OVER (PARTITION BY col1) sum_col2
FROM tab1)
WHERE ( ( sum_col2 <> 0
AND col2 <> 0)
OR sum_col2 = 0)

SELECT t1.*
FROM tab1 t1
JOIN (SELECT "col1", MAX("col2") AS max2
FROM tab1
GROUP BY "col1") t2
ON t1."col1" = t2."col1"
WHERE ((max2 = 0 AND "col2" = 0)
OR
(max2 != 0 AND "col2" != 0))
ORDER BY "rownum"
DEMO

Related

Can I change column order in SQL table based on a value that appears in different columns?

I have a table that looks like this:
Column1 | Column2 | Column3| Column4
4 | 3 | 2 | 1
2 | 1
3 | 2 | 1
I want to flip the columns so that 1 always start in column 1 and then the rest of the values follow to the right. Like this:
Column1 | Column2 | Column3 | Column4
1 | 2 | 3 | 4
1 | 2
1 | 2 | 3
This is an example table. The real table is a hierarchy of a company so 1 = CEO and 2 = SVP for example. 1 is always the same name but as the number gets higher (lower in chain of command) the more names that are in that level. I'm hoping for an automated solution that looks for 1, makes that the first column and then populates the columns. I am struggling because the value that 1 represents is in different columns so I can't just change the order of the columns.
I was able to accomplish this using VBA but I would prefer to keep it in SQL.
I don't have any useful code that I have tried so far.
You can use Case expression:
WITH CTE1 AS
(SELECT 4 AS COL1, 3 AS COL2 , 2 AS COL3, 1 AS COL4 FROM DUAL
UNION ALL
SELECT 2, 1, NULL, NULL FROM DUAL
UNION ALL
SELECT 3, 2, 1, NULL FROM DUAL
)
SELECT CASE WHEN COL1 <> 1 THEN 1 ELSE COL1 END AS COL1,
CASE WHEN COL2 <> 2 THEN 2 ELSE COL2 END AS COL2,
CASE WHEN COL3 <> 3 THEN 3 ELSE COL3 END AS COL3,
CASE WHEN COL4 <> 4 THEN 4 ELSE COL4 END AS COL4
FROM CTE1;
You can apply some CASEes checking all possibilities, this is assuming NULLs for missing data:
COALESCE(col4,col3,col2,col1) AS c1,
CASE
WHEN col4 IS NOT NULL THEN col3
WHEN col3 IS NOT NULL THEN col2
WHEN col2 IS NOT NULL THEN col1
END AS c2,
CASE
WHEN col4 IS NOT NULL THEN col2
WHEN col3 IS NOT NULL THEN col1
END AS c3,
CASE
WHEN col4 IS NOT NULL THEN col1
END AS c4
You want to sort the values. A generic SQL solution would use:
select max(case when seqnum = 1 then col end) as col1,
max(case when seqnum = 2 then col end) as col2,
max(case when seqnum = 3 then col end) as col3,
max(case when seqnum = 4 then col end) as col4
from (select col1, col2, col3, col4, col,
row_number() over (order by col) as seqnum
from ((select col1 as col, 1 as which, col1, col2, col3, col4 from t) union all
(select col2 as col, 2 as which, col1, col2, col3, col4 from t) union all
(select col3 as col, 3 as which, col1, col2, col3, col4 from t) union all
(select col4 as col, 4 as which, col1, col2, col3, col4 from t)
) t
where col is not null
) t
group by col1, col2, col3, col4;
This would be simpler in a database that supports lateral joins. And a unique id on each row would also help.

Sqlite insert both even and odd rows in one expression

I am using sqlite3 and I have a sqlite table which has somewhat duplicated/overlapping columns. To illustrate:
No Col1 Col2 Col3 Col4
row1 1 1 1 2 2
row2 2 1 1 3 3
row3 3 2 2 4 4
row4 4 2 2 5 5
Col1 and Col2 stores the same information, however, Col3 and Col4 has different information.
I want to condense the rows into one row like this:
No Col1 Col2 Col3 Col4 Col3.2 Col4.2
row1 1 1 1 2 2 3 3
row3 3 2 2 4 4 5 5
I have created a new table with the columns, and was able to select the odd rows.
INSERT INTO [Table] ( No, Col1, Col2, Col3, Col4
)
SELECT No, Col1, Col2, Col3, Col4
FROM [Table]
WHERE ([No] % 2) = 1
ORDER BY [No];
The result table would be something like:
No Col1 Col2 Col3 Col4 Col3.2 Col4.2
row1 1 1 1 2 2 null null
row3 3 2 2 4 4 null null
Now I am not sure how to insert the even values into the new table. Using similar expressions only insert more rows. Is it possible to do this INSERT INTO expression in one sentence? Or how do I update the new table?
Just join the table with itself based on the following condition. It'll even work if the No column has gaps:
SELECT o.No, o.Col1, o.Col2, o.Col3, o.Col4, e.Col3, e.Col4
FROM t AS o
INNER JOIN t AS e ON o.Col1 = e.Col1
AND o.Col2 = e.Col2
AND o.No < e.No
Use pivoting logic with aggregation:
SELECT
MIN(No) AS No,
MAX(CASE WHEN No % 2 = 1 THEN Col1 END) AS Col1,
MAX(CASE WHEN No % 2 = 1 THEN Col2 END) AS Col2,
MAX(CASE WHEN No % 2 = 1 THEN Col3 END) AS Col3,
MAX(CASE WHEN No % 2 = 1 THEN Col4 END) AS Col4,
MAX(CASE WHEN No % 2 = 0 THEN Col1 END) AS Col1_2,
MAX(CASE WHEN No % 2 = 0 THEN Col2 END) AS Col2_2,
MAX(CASE WHEN No % 2 = 0 THEN Col3 END) AS Col3_2,
MAX(CASE WHEN No % 2 = 0 THEN Col4 END) AS Col4_2
FROM yourTable
GROUP BY
(No-1) / 2;
Demo
Another approach, using window functions added in sqlite 3.25:
CREATE TABLE table2(no INTEGER PRIMARY KEY, col1, col2, col3, col4, "col3.2", "col4.2");
INSERT INTO table2
SELECT *
FROM (SELECT no, col1, col2, col3, col4, lead(col3) OVER win, lead(col4) OVER win
FROM table1
WINDOW win AS (ORDER BY no))
WHERE no % 2 = 1;
which gives
SELECT * FROM table2;
no col1 col2 col3 col4 col3.2 col4.2
---------- ---------- ---------- ---------- ---------- ---------- ----------
1 1 1 2 2 3 3
3 2 2 4 4 5 5

Count per category

have a table as below -
COL1 | COL2 | COL3
1 1 1
1 1 2
1 2 0
1 2 1
2 3 1
2 3 2
2 4 0
2 4 1
3 1 0
3 2 0
.
.
.
I want to select COL1 where all COL2 have sum(COL3) is > 0. If I am sure there are 20 distinct values in COL2, Then how can i pull all COL1 values that have all 20 COL2 filled with COL3 > 0. So the end result should be
COL1 | COL2 | COL3
1 1 3
1 2 1
2 3 3
2 4 1
I have tried a lot of ways to do this but no success.
Just use group by and having.
select col1,col2,sum(col3)
from tbl
group by col1,col2
having sum(col3)>0
select t1.*
from yourTable t1
inner join
(
select t.col1
from
(
select col1, col2, sum(col3) as col_sum
from yourTable
group by col1, col2
) t
group by t.col1
having sum(case when t.col_sum = 0 then 1 else 0 end) = 0
) t2
on t1.col1 = t2.col1
I use a CTE and a Group by with a where condition
;WITH CTE as (
select COL1,COL2,SUM(COL3) as COL3 FROM table1
Group By
COL1,COL2
)
select * from CTE
where COL3>0
Just group col2 and check if it's bigger then 0
select col1,col2,sum(col3)
from tbl
group by col2
having sum(col3)>0
http://sqlfiddle.com/#!9/537f8c/1
See if the below gives you the result that you are after. It is selecting the col1, col2 and a sum of col3 from a derived(?) table that is excluding the col3's that are 0:
select col1, col2, sum(col3)
from
(
select col1, col2, col3 from tbl where col3 <> 0
) as ds
group by col3

SQL how to highlight duplicates under some conditions

I need to mark dupliactes in the data buy only under some complex conditions. Let's say I have a table like this:
col1 col2
1 a
1 a
1 a
2 #B
2 #B
1 a
3 #B
3 #B
2 #B
1 a
4 #A
4 #A
5 c
I need to mark those records where:
value in col2 begins with a '#' AND ( it is a duplicate value in col2 AND it is under different values in col1).
so I need to get this:
col1 col2 newcol
1 a
1 a
1 a
2 #B 1
2 #B 1
1 a
3 #B 1
3 #B 1
2 #B 1
1 a
4 #A
4 #A
5 c
the reason why rows with "#B" in col2 are marked is because it is a duplicate in col2 AND "#B" can be found under "3" and "2" (so 2 or more different values) in col1. The reson why records with "#A" are NOT marked is because while the are a duplicate in col2 they are only under one value ("4") in col1.
I am working in dashDB
I think DashDB supports window functions. If so, you can do:
select col1, col2,
(case when min_col1 <> max_col1 then 1 end) as flag
from (select t.*,
min(col1) over (partition by col2) as min_col1,
max(col1) over (partition by col2) as max_col1
from t
) t;
You can also do something similar without window functions.
Here is an alternative method:
select t.*, t2.flag
from t join
(select col2,
(case when min(col1) <> max(col1) then 1 end) as flag
from t
group by col2
) t2
on t.col2 = t2.col2;

SQL where column equals Val and equals Val2

If you have a table as per bellow:
Col1 Col2
1 1
2 1
3 1
1 2
3 2
2 3
is there a way to write a SQL query where (Col2 =1 and Col2=2) and the result is:
Col1
1
3
You could do this using intersect. Note that this wouldn't work in MySQL.
select col1 from tablename where col2 = 1
intersect
select col1 from tablename where col2 = 2
You can use HAVING with CASE WHEN:
SELECT Col1
FROM your_table
GROUP BY Col1
HAVING SUM(CASE WHEN Col2 = 1 THEN 1 END) > 0
AND SUM(CASE WHEN Col2 = 2 THEN 1 END) > 0;
LiveDemo
With MySQL you can write:
SELECT Col1
FROM your_table
GROUP BY Col1
HAVING SUM(Col2 = 1) > 0
AND SUM(Col2 = 2) > 0;
Self join version:
select distinct t1.col1
from (select col1 from tablename where col2 = 1) t1
join (select col1 from tablename where col2 = 2) t2 on t1.col1 = t2.col1