Conditional count over multiple tables - sql

Is there a simpler way to count the number of rows in different tables that fulfill the same conditions?
For example, I want to separately count the number of rows in the following two tables that correspond to certain IDs:
Select
'table1' as tablename, count(*) as rownr from table1
where SOMEID in ('1815972751','1815751159','1815752967','1815756079')
union all
Select
'table2' as tablename, count(*) as rownr from table2
where SOMEID in ('1815972751','1815751159','1815752967','1815756079') ;
The result would be something like
table1 | 21
table2 | 54
However, I would like to only define the condition (in this case, the IDs) once, for example in a variable or list, so they area easily manageable.

Here is one way:
select tablename, count(*)
from (select 'table1' as tablename, someid
from table1
union all
select 'table2' as tablename, someid
from table2
) t
where someid in ('1815972751', '1815751159', '1815752967', '1815756079')
group by tablename;
Do note that performance may not be as good as in your original version.

Related

SQL check or uniqueness in one column in multipe tables

I have a 'unique' column, 'GID_New' that is in multiple tables. Is there a way to check if it's unique across all the tables in the QGIS project in SQL?
Can it be done in one SQL search without merging the tables into one and then running something like
SELECT A.GID_New, count(*), A.TableName
FROM "Water_Merged" as A
Group by A.GID_New
And then checking for a count >1
I would like to know which table the non-unique GID_New's are from as well.
The data is in a geopackage in QGIS so the code needs to work in QGIS SQL implementation.
You can use union all:
select gid_new, count(*) no_matches
from (
select gid_new from table1
union all select gid_new from table2
union all select gid_new from table3
) t
group by gid
having count(*) > 1
If you want to know in which table duplicates exists, then one option is string concatenation. Assuming that your database uses string_agg(), that would look like:
select gid_new, count(*) no_matches, string_agg(which, ',') which_tables
from (
select 'table1' which, gid_new from table1
union all select 'table2', gid_new from table2
union all select 'table3', gid_new from table3
) t
group by gid
having count(*) > 1

Select avg from each table

I would like to query multiple tables and get an average count of store_key from each, using a fairly elaborate set of WHERE criteria for each. I can query them all separately, but I'd like to do this in one query.
Each table has retailer_key, store_key (as well as many other columns)
I would like my query to return something that looks like:
Table Name | AVG # of store keys
Using a where condition similar to WHERE retailer_key = 41 AND... Using columns that each of these tables share.
Does that make any sense? It seems really simple, but for some reason I can't figure out how to build the query.
You could use a series of union all operators:
SELECT table_name, AVG(store_key)
FROM (SELECT 'table1' AS table_name, store_key, retailer_key
FROM table1
UNION ALL
SELECT 'table2' AS table_name, store_key, retailer_key
FROM table2
UNION ALL
SELECT 'table3' AS table_name, store_key, retailer_key
FROM table3
-- More queries like this if needed...
) t
WHERE retailer_key = 41 -- AND additional conditions
GROUP BY table_name

How to check if multiple tables have rows for given ID

I have master table with several details tables. I need to check if each of the details tables have any rows for given ID. Right now I am going through all the tables and checking if count>0 but there must be a better way.
SELECT COUNT(*) FROM Table1 WHERE ID=3;
SELECT COUNT(*) FROM Table2 WHERE ID=3;
...
SELECT COUNT(*) FROM TableN WHERE ID=3;
Is there a way to do this in one effective SQL statement?
WITH CTE AS
(
SELECT 'T1' AS Name, COUNT(*) AS Total FROM Table1 WHERE ID=3
UNION ALL
SELECT 'T2' AS Name, COUNT(*) AS Total FROM Table2 WHERE ID=3
UNION ALL
...
UNION ALL
SELECT 'Tn' AS Name, COUNT(*) AS Total FROM TableN WHERE ID=3;
)
Select * from CTE where Total > 0
This sounds like poor design of your tables. I think you need to either combine some tables or add a bridge table that you can query.
Or, keep querying the individual tables if you structure is optimal and just have your application deal with running each one.
If you really want one result set you can do:
DECLARE #ID INT
SET #ID = 3
SELECT 'Table1' TableName, COUNT(*) FROM Table1 WHERE ID=#ID;
UNION
SELECT 'Table2' TableName, COUNT(*) FROM Table2 WHERE ID=#ID;
UNION
...
UNION
SELECT 'TableN' TableName, COUNT(*) FROM TableN WHERE ID=#ID;
I don't see a way to not scan all tables if that's what you're trying to avoid.

How to select the name of the table in an SQL query?

I'm using a UNION and a LIMIT to select the earliest occurence of a type of table row from multiple tables. I need a record of which table satisfied the query in the result set.
Is there a way of doing something like:
SELECT id, someField, tableName FROM someUnknownTable WHERE someConditions = true
You can select your tableName as a constant value:
Select id, someField, 'Table1' As tableName
From table1
Union
Select id, someField, 'Table2' As tableName
From table2
The second alias (As tableName) can be omitted.

MySQL UNION print every other

How can I make a sql query like the following:
(SELECT `name` FROM table1)
UNION
(SELECT `name` FROM table2)
return each other. Ie. name1 from table1, name1 from table2, name2 from table1, name2 from table2 and so on?
Edit:
Table1
name
Hello
world
Table2
name
guten
tag
The output wanted:
Hello
guten
world
tag
and this should also be possible if adding more unions, so that it takes from the first union, then the second, third, forth and so on.
You could number rows with variables, using 2,4,6,... for the first part of the union and 3,5,7,... for the second:
select #rownum1 := #rownum1+2 as rownum, name
from (select #rownum1:=0) r, table1
union all
select #rownum2 := #rownum2+2 as rownum, name
from (select #rownum2:=1) r, table2
order by rownum;
The select in the from clause (select #rownum2:=1) r is only used to initialize the variable.
Does this work?
set #i = 0;
set #j = 1;
select #i:=#i+2 as rownumber,
name
from table1
union
select #j:=#j+2 as rownumber,
name
from table2
order by rownumber
I read your question as wanting to alternate one row from table1, one from table2 and so on in your results set.
Edit in light of your edit:
Change the "2"s to the number of tables, and add as many variables as you have tables, with consecutive start values in the "set" statements. This will extend in the way you want.
In a similar vein to David M, you can do:
(SELECT #rownum:=#rownum+1 as rownum,`name` FROM table1, (SELECT #rownum:=0) r)
UNION
(SELECT #rownum:=#rownum+1 as rownum,`name` FROM table2, (SELECT #rownum:=0) r)
order by rownum