SQL: Ignore Condition in WHERE clause - sql

I am confused on how to exclude one of the conditions in WHERE clause if it evaluates to NULL
SELECT TB1.COL3
FROM TB1, TB2
WHERE TB1.COL1 = TB2.Col1
AND TB2.COL1 = '12345'
AND (TB2.COL3 = (SELECT MIN(TB3.COL4)
FROM TB3
WHERE COL1 = TB2.COL1
AND COL2 in ('A', 'B')
AND COL4 IN (SELECT COL3 FROM TB4
WHERE COL1 = TB4.COL1)))
AND ROWNUM = 1;
How can I modify the above query to ignore the "AND condition TB2.COL3" if the following condition SELECT MIN(TB3.COL4) FROM TB3 evaluates to some value except NULL. If NULL the above query should be executed as below:
SELECT TB1.COL3
FROM TB1, TB2
WHERE TB1.COL1 = TB2.Col1
AND TB2.COL1 = '12345'
AND ROWNUM = 1;

I think you could pull this off with a coalesce:
SELECT TB1.COL3
FROM TB1, TB2
WHERE TB1.COL1 = TB2.Col1
AND TB2.COL1 = '12345'
AND (TB2.COL3 = COALESCE((SELECT MIN(TB3.COL4)
FROM TB3
WHERE COL1 = TB2.COL1
AND COL2 in ('A', 'B')
AND COL4 IN (SELECT COL3 FROM TB2
WHERE COL1 = TB2.COL1)), TB2.COL3))
AND ROWNUM = 1;
Here we are just wrapping that SELECT statement in COALESCE which, if it returns null, will grab the second parameter's value instead, which is the same column we are comparing. Since TB2.COL3 = TB2.COL3 is obviously TRUE then this filter will not have any impact on the result set.
Also, it's generally recommended that you stop using comma's in your FROM clause and use proper JOIN syntax. It's been around for over 2 decades now:
SELECT
TB1.COL3
FROM
TB1
INNER JOIN TB2
ON TB1.COL1 = TB2.Col1
WHERE
TB2.COL1 = '12345'
AND
(
TB2.COL3 = COALESCE
(
(
SELECT
MIN(TB3.COL4)
FROM
TB3
WHERE
COL1 = TB2.COL1
AND COL2 in ('A', 'B')
AND COL4 IN
(
SELECT
COL3
FROM
TB2
WHERE
COL1 = TB2.COL1
)
),
TB2.COL3
)
)
AND ROWNUM = 1;

Related

SQL: How to compare two rows from same table where second row is given by first's values

Below is my SQL Server query which works great, but as you can see I am fetching the same row multiple times. Is there a way to optimise this by doing a SELECT only once? Thanks.
SELECT TOP 1 1
FROM some_table
WHERE col1 = #col1
AND (col2 IN ('N', 'C', 'U') OR
col3 != (SELECT t.col3 FROM some_table t
WHERE t.id = id AND t.revision_id = revision_id - 1) OR
col4 != (SELECT t.col4 FROM some_table t
WHERE t.id = id AND t.revision_id = revision_id - 1) OR
col5 != (SELECT t.col5 FROM some_table t
WHERE t.id = id AND t.revision_id = revision_id - 1) OR
col6 != (SELECT t.col6 FROM some_table t
WHERE t.id = id AND t.revision_id = revision_id - 1)
)
Note: I only need to see only if one such column exists (see SELECT 1 1), which is more than likely to give be 1 most times. So I do NOT want to do a join of the table which has millions of rows.
First, you have an error with the column names in the subqueries. See Qualifying column names in subqueries
column names in a statement are implicitly qualified by the table referenced in the FROM clause at the same level.
So, all of these columns belong to t: t.id=id AND t.revision_id=revision_id-1
And the query:
SELECT TOP 1 1
FROM some_table s
WHERE col1=#col1
AND
(
col2 IN ('N','C','U') OR
EXISTS(SELECT * FROM some_table where id = s.id
AND revision_id = s.revision_id - 1 AND
(col3 != s.col3 OR col4 != s.col4 OR col5 != s.col5 OR col6 != s.col6)
)
)
You can use apply here to select multiple columns form a related row.
This is just an approximation of what you need as you haven't supplied any example data and expected results. You may need to use a top (1) with an appropriate order by clause or aggregate if the apply can return more than one row:
select *
from some_table t
outer apply (
select col3, col4, col5, col6
from some_table t2
where t2.id = t.id AND t2.revision_id = t.revision_id-1
)t2
where col1 = #col1
and (
col2 IN ('N','C','U') or
t.col3 != t2.col3 or
t.col4 != t2.col4 or
t.col5 != t2.col5 or
t.col6 != t2.col6
);

Remove inner query in SQL

We have a SQL query which is not written as per the sql guideline. We have to change the query but if we change the logic and remove the inner query then it take to much time to execute. Below is the query:
select col1,
col2,
case
when col1 <> '' then(select top 1
col1
from table1 as BP
where bp.col1 = FD.col1 order by BP.col1)
when col2 <> '' then(select top 1
BP.col2
from table1 as BP
where BP.col2 = FD.col2 order by BP.col2)
else ''
end
from table2 FD
The above query is being used to insert the data into a temp table. The table1 has almost 100 million of data. Is there any way to remove the inline query along with the good performance. We have already created the indexes on table1. Any thought?
Try this
;WITH CTE
AS
(
SELECT
RN = ROW_NUMBER() OVER(ORDER BY COALESCE(T2.col1,T2.col2)),
T2.col1,
T2.col2,
T1Val = COALESCE(T2.col1,T2.col2,'')
FROM table2 T2
LEFT JOIN table1 T1
ON
(
(
ISNULL(T2.col1,'')<>'' AND T1.col1 = T2.col1
)
OR
(
ISNULL(T2.col2,'')<>'' AND T1.col2 = T2.col2
)
)
)
SELECT
*
FROM CTE
WHERE RN = 1
Here is my modest help:
You can already prepare and materialize your subquery1 and subquery2 (Group BY col1 or col2) <-- It will reduce the size of your table 1)
Split your main query (from table2 into 3 different queries)
1 with SELECT .. FROM table2 WHERE col1 <> ''
1 with SELECT .. FROM table2 WHERE col1 = '' AND col2 <> ''
1 with SELECT .. FROM table2 WHERE col1 = '' AND col2 = ''
Use an INNER JOIN with your table created in the first point.
(If you use SSIS you can // and use your inner join table into a Lookup)
If your col1 or col2 use a NVARCHAR(MAX) or a big size, you should have a look to a HashFunction (MD5 for example) and compare Hash instead.
Be sure to have all your indexes
At least if it is not performant, you can try with:
OUTER APPLY (SELECT TOP 1 .. )
Another idea should be:
SELECT col1, col2, col1 AS yourNewCol
FROM table2 T2
WHERE EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col1 = T2.col1)
UNION ALL
SELECT col1, col2, col2 AS yourNewCol
FROM table2 T2
WHERE
NOT EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col1 = T2.col1)
AND EXISTS( SELECT 1 FROM table1 T1 WHERE T1.col2 = T2.col2)
UNION ALL
...
I don't have a clean solution for you, but some ideas.
Let me know if it helps you.
Regards,
Arnaud

MSSQL: How to add a column with a sum of three others

I have a table with three columns
SELECT
(SELECT COUNT(*) FROM Table1 WHERE IDU = 406536063) as 'col1',
(SELECT COUNT(*) FROM Table2 WHERE CustomerNr = 406536063) as 'col2',
(SELECT COUNT(*) FROM Table3 WHERE CustomerNr = 406536063) as 'col3'
How can I add in MSSQL the forth column with the sum of values in col1, col2, col3?
You can also move the queries to the FROM clause:
SELECT col1, col2, col3, (col1 + col2 + col3)
FROM (SELECT COUNT(*) as col1 FROM Table1 WHERE IDU = 406536063) t1 CROSS JOIN
(SELECT COUNT(*) as col2 FROM Table2 WHERE CustomerNr = 406536063) t2 CROSS JOIN
(SELECT COUNT(*) as col3 FROM Table3 WHERE CustomerNr = 406536063) t3;
Although I do use subqueries in the SELECT, I usually put them in the FROM clause.
Using cte might help:
;with cte (col1,col2,col3) as
(
SELECT
(SELECT COUNT(*) FROM Table1 WHERE IDU = 406536063) as 'col1',
(SELECT COUNT(*) FROM Table2 WHERE CustomerNr = 406536063) as 'col2',
(SELECT COUNT(*) FROM Table3 WHERE CustomerNr = 406536063) as 'col3'
)
select col1+col2+col3
from cte

Oracle Query with AND and OR

How can I write the following scenario as query in Oracle
SELECT *
FROM table1
WHERE col1 = 'SOMENAME' WITH (EITHER COL2 = 'Y' OR COL3 = 'Y')
You need to use AND:
Select *
from table1
where col1 = 'SOMENAME'
AND (COL2 = 'Y' OR COL3 = 'Y')

Difference between these two update SQL statements in Oracle?

What's the difference between these two update SQL statements in Oracle
First:
UPDATE t1
SET col1 = 'Y'
WHERE EXISTS (SELECT *
FROM t2
WHERE t1.p1 = t2.p1
AND t1.p2 = t2.p2
AND t2.col3 = 'a'
AND t1.p1 = 'b'
AND t1.p2 = 'c')
Second:
UPDATE t1
SET col1 = 'Y'
WHERE EXISTS (SELECT *
FROM t2
WHERE t1.p1 = t2.p1
AND t1.p2 = t2.p2
AND t2.col3 = 'a')
AND t1.p1 = 'b'
AND t1.p2 = 'c'
there is no difference at all - they have the same meaning