SQL if statement within WHERE clause - sql

I want to do the following query, how can I implement it?
SELECT * FROM table WHERE routeNum LIKE 'N10%'
-->if no rows return, WHERE clause change to routeName LIKE '&something%'

I think this will work for you:
WITH CTE AS (
SELECT 2 AS 'INDEX', * FROM table WHERE routeNum LIKE 'N10%'
UNION ALL
SELECT 1 AS 'INDEX', * FROM table WHERE routeNum LIKE '&something%'
)
SELECT *
FROM CTE
WHERE CTE.INDEX = (SELECT MAX(INDEX) FROM CTE)
As you have to choose between two result sets, you will need two queries, which will return two different sets and then, based on the 'index' which corresponds to the query that has run, you choose how to display your results.
Here is a SQLFiddle demo.

A possible solution
WITH cte AS
(
SELECT *
FROM routes
WHERE routeNum LIKE 'N10%'
)
SELECT * FROM cte
UNION ALL
SELECT * FROM routes
WHERE routeNum LIKE 'something else%'
AND NOT EXISTS
(
SELECT *
FROM cte
)
Here is SQLFiddle demo

WITH tmp AS
(
SELECT t.*,
CASE
WHEN routeNum LIKE 'N10%' THEN 1
WHEN routeNum LIKE '&something%' THEN 2
ELSE 3 END AS q
FROM table t
)
SELECT * FROM tmp t
WHERE q = CASE WHEN (SELECT COUNT(*) FROM tmp WHERE q = 1 ) > 0 THEN 1 ELSE 2 END

Related

How to check result of a query using IF scripting in BigQuery?

I have a query and I want to check if the output has at least one row, if not , show some message like "No data". I have tried like described here : https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting#if
WITH
cte1 AS (
SELECT id, name
FROM My_table
)
SELECT
* from cte1;
IF (SELECT COUNT(*) = 0 FROM cte1) THEN SELECT "No data"; END IF
You can do something like this:
WITH cte1 AS (
SELECT id, name
FROM My_table
)
SELECT id, name
FROM cte1;
UNION ALL
SELECT NULL, 'No Data'
FROM (SELECT 1 as x) x
WHERE NOT EXISTS (SELECT 1 FROM cte2);
Note: The subqueries need to return the same columns.

BigQuery SQL conditional IN

I have been trying to construct a conditional IN like below, but this gives me the scalar subquery produced more than one element error. How should I approach this type of query instead? The tables are not related.
select * from my_table
where my_table.my_col in (
case
when 1 = 1
then (select my_col from my_other_table_1)
else (select my_col from my_other_table_2)
end
)
Try this below-
select * from my_table
where my_table.my_col in (
SELECT
case
when 1 = 1 then my_col_1
else my_col_2
END
from my_other_table
)
As your other tables are not related, you can try this below logic-
select * from my_table
where
(1=1 and my_col IN (select my_col_1 from my_other_table_01)
OR
(3=3 and my_col IN (select my_col_2 from my_other_table_02)

Pattern matching SQL on first 5 characters

I'm thinking about a SQL query that returns me all entries from a column whose first 5 characters match. Any ideas?
I'm thinking about entries where ANY first 5 characters match, not specific ones. E.g.
HelloA
HelloB
ThereC
ThereD
Something
would return the first four entries:
HelloA
HelloB
ThereC
ThereD
EDIT: I am using SQL92 so cannot use the left command!
Try this :
SELECT *
FROM YourTable
WHERE LEFT(stringColumn, 5) IN (
SELECT LEFT(stringColumn, 5)
FROM YOURTABLE
GROUP BY LEFT(stringColumn, 5)
HAVING COUNT(*) > 1
)
SQLFIDDLE DEMO
This selects the first 5 characters, groups by them and returns only the ones that happen more than once.
Or with Substring:
SELECT * FROM YourTable
WHERE substring(stringColumn,1,5) IN (
SELECT substring(stringColumn,1,5)
FROM YOURTABLE
GROUP BY substring(stringColumn,1,5)
HAVING COUNT(*) > 1)
;
SQLFIDDLE DEMO
Sounds easy enough...
In SQL Server this would be something along the lines of
where Left(ColumnName,5) = '12345'
Try
Select *
From tbl t1
Where exists (
Select 1
From tbl t2
Where left(t1.str, 5) = left(t2.str)
Group by left(t2.str, 5)
Having count(1) > 1
)
You didn't specify your DBMS. If it supports Windowed Aggregate functions it's:
select *
from
(
select
tab.*,
count(*) over (partition by substring(col from 1 for 5) as cnt
from tab
) as dt
where cnt > 1
You want to work with a CTE approach.
Something like this:
with CountriesCTE(Id, Name)
as (
select Id, Name from Countries
)
select distinct Countries.Name
from CountriesCTE, Countries
where left(CountriesCTE.Name,5) = left(Countries.Name,5) and CountriesCTE.Id <> Countries.Id

sql with clause within a with clause

can i do something like this :
with t as
(
with tt as
(
select * from table
)
SELECT * FROM tt
)
select * from t
i willing to perform some logic on output of inner with clause & than again do some operations on output of the outer with clause.
any help will be appreciated ...
Thanks
note :- its just some simplified query that will resolve my problem in my actual query, which have nested with clause
You can do something like this:
with t as
(
select * from table
),
tt as
(
select * from t
)
select * from tt
No, you cannot nest CTE (Common Table Expression) but you can chain them:
with t as
(
select * from table
),
tt as
(
select * from t
)
SELECT * FROM tt

SQL Server Top 1

In Microsoft SQL Server 2005 or above, I would like to get the first row, and if there is no matching row, then return a row with default values.
SELECT TOP 1 ID,Name
FROM TableName
UNION ALL
SELECT 0,''
ORDER BY ID DESC
This works, except that it returns two rows if there is data in the table, and 1 row if not.
I'd like it to always return 1 row.
I think it has something to do with EXISTS, but I'm not sure.
It would be something like:
SELECT TOP 1 * FROM Contact
WHERE EXISTS(select * from contact)
But if not EXISTS, then SELECT 0,''
What happens when the table is very full and you might want to specify which row of your top 1 to get, such as the first name? OMG Ponies' query will return the wrong answer in that case if you just change the ORDER BY clause. His query also costs about 8% more CPU than this modification (though it has equal reads)
SELECT TOP 1 *
FROM (
SELECT TOP 1 ID,Name
FROM TableName
ORDER BY Name
UNION ALL
SELECT 0,''
) X
ORDER BY ID DESC
The difference is that the inner query has a TOP 1 also, and which TOP 1 can be specified there (as shown).
Just for fun, this is another way to do it which performs very closely to the above query (-15ms to +30ms). While it's more complicated than necessary for such a simple query, it demonstrates a technique that I don't see other SQL folks using very often.
SELECT
ID = Coalesce(T.ID, 0),
Name = Coalesce(T.Name, '')
FROM
(SELECT 1) X (Num)
LEFT JOIN (
SELECT TOP 1 ID, Name
FROM TableName
ORDER BY ID DESC
) T ON 1 = 1 -- effective cross join but does not limit rows in the first table
Use:
SELECT TOP 1
x.id,
x.name
FROM (SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'') x
ORDER BY id DESC
Using a CTE equivalent:
WITH query AS (
SELECT t.id,
t.name
FROM TABLENAME t
UNION ALL
SELECT 0,
'')
SELECT TOP 1
x.id,
x.name
FROM query x
ORDER BY x.id DESC
CREATE TABLE #sample(id INT, data VARCHAR(10))
SELECT TOP 1 id, data INTO #temp FROM #sample
IF ##ROWCOUNT = 0 INSERT INTO #temp VALUES (null, null)
SELECT * FROM #temp
put the top oustide of the UNION query
SELECT TOP 1 * FROM(
SELECT ID,Name
FROM TableName
UNION ALL
SELECT 0,''
) z
ORDER BY ID DESC
IF EXISTS ( SELECT TOP 1 ID, Name FROM TableName )
BEGIN
SELECT TOP 1 ID, Name FROM TableName
END
ELSE
BEGIN
--exists returned no rows
--send a default row
SELECT 0, ''
END