Dynamic JOIN of multiple tables in SQL - google-bigquery

I am creating a procedure in Bigquery to generate a table with the union of data from several tables.
The total number of tables is stored in an array that can vary in content.
This is an example of what I have:
DECLARE dataset STRING DEFAULT "MY_DATASET";
DECLARE tablesArray ARRAY<STRING>;
SET tablesArray = ['TABLE_ONE','TABLE_TWO']
This is what I want to achieve:
SELECT * FROM MY_DATASET.TABLE_ONE
UNION ALL
SELECT * FROM MY_DATASET.TABLE_TWO
How can you build this into a procedure efficiently?

You can use a dynamic SQL in BigQuery script.
EXECUTE IMMEDIATE
DECLARE dataset STRING DEFAULT "MY_DATASET";
DECLARE tablesArray ARRAY<STRING>;
SET tablesArray = ['TABLE_ONE','TABLE_TWO'];
EXECUTE IMMEDIATE (
SELECT STRING_AGG('SELECT * FROM `MY_DATASET.'|| t || '`', '\n UNION ALL\n')
FROM UNNEST(tablesArray) t
);
SELECT * FROM `MY_DATASET.TABLE_ONE`
UNION ALL
SELECT * FROM `MY_DATASET.TABLE_TWO`

Related

nested select query with table name in sqlite

I am trying to select all distinct values from all tables that start with a specific name, like: 'logs_2020_12_01', 'logs_2021_01_02', ..To select all tables with this specific name is straight forward:
SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%';
The select I want for one individual table is:
SELECT DISTINCT batch FROM logs_2021_01_27;
but I cannot find a way to combine it to make the selection from all tables. I tried a couple of things but it does not work, like:
SELECT DISTINCT batch FROM (SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%')
any ideas?
thanks
What about using Dynamic SQL, stored your tables information into a temp table with id column and set it to identity.
CREATE TABLE #temp ---identity column will be used to iterate
(
id INT IDENTITY,
TableName VARCHAR(20)
)
INSERT INTO #temp
SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'logs_%';
-- choose your own results with where conditions
DECLARE #SQL VARCHAR(MAX)
DECLARE #Count INT = 1
DECLARE #Table VARCHAR(20)
WHILE #COUNT <= (SELECT COUNT(*) FROM #temp)
BEGIN
select #table = TABLENAME FROM #temp WHERE id = #Count
SELECT #sql = 'SELECT DISTINCT(batch) FROM '+ #table
PRINT #SQL
SET #Count = #Count + 1
END
after your print result looks good, change it to EXEC(#SQL), thanks
SQLite does not support dynamic sql.
You have to select the column batch from each of all the tables and combine them with UNION so the duplicates are removed:
SELECT batch FROM logs_2020_12_01 UNION
SELECT batch FROM logs_2020_12_02 UNION
......................................
SELECT batch FROM logs_2020_12_30 UNION
SELECT batch FROM logs_2020_12_31
If you don't know the full names of the tables, you can get them with this statement:
SELECT name
FROM sqlite_master
WHERE type = 'table' AND name LIKE 'logs/_%' ESCAPE '/'
and then use a programming language to construct a SELECT statement with UNION to get the results that you want.

Returning both a table and a scalar from a stored procedure in MSSQL Server

I want to return both table data AND a count of the table data through an OUT parameter from a SP. The count isn't of the table data in it's final state, rather it's the table data pre doing TOP 100 to return just 100 rows. I think the following does what I want, but is there a more efficient way to achieve this?
CREATE PROC sp_total_recs
#total_recs INT OUT
AS
BEGIN
-- return top 100 records only
SELECT TOP 100 *
INTO #temp
FROM
(
SELECT *, COUNT(1) OVER () AS total_records
FROM table
) T;
SET #total_recs = (SELECT DISTINCT total_records FROM #temp);
SELECT *
FROM #temp;
DROP TABLE #temp;
RETURN
END;
DECLARE #tot_recs INT;
EXEC sp_total_recs
#total_recs = #tot_recs OUTPUT;

dynamic sql count in a variable

This query works
select #V_COUNT =COUNT(1) from TAB1
But I want to pass the table as variable how to do that in sybase ?
i tried this but didnt work
select #V_COUNT ='COUNT(1) from ''||#TMP_TABLE_NAME||'''
select #LL_COUNT = CONVERT(numeric(30),#V_COUNT)
edit:
i did this
SELECT #V_COUNT ='SELECT COUNT(1) from '+ #TABLE_NAME
execute (#V_COUNT)
SELECT #LL_COUNT = 'SELECT convert(NUMERIC(6),'||#V_COUNT||')'
Implicit conversion from datatype 'VARCHAR' to 'NUMERIC' is not
allowed. Use the CONVERT function to run this query.
You need to execute that dynamic query, using:
CREATE TABLE #Count(x int)
SELECT #sSQL = "INSERT #Count SELECT COUNT(1) from "+ #TMP_TABLE_NAME
execute (#sSQL)
SELECT #V_COUNT = x from #Count
DROP TABLE #Count
SELECT #LL_COUNT = (SELECT convert(NUMERIC(30,4), #V_COUNT))
SELECT #LL_COUNT
where #TMP_TABLE_NAME might be SELECT #TMP_TABLE_NAME = 'tablename' is simple string which you don't need to execute or get result from.

Create Table, insert values and then select those within stored procedure

I have this stored procedure:
CREATE or replace PROCEDURE TESTx()
BEGIN
DECLARE tableOneCount INTEGER;
DECLARE tableTwoCount INTEGER;
DECLARE strCmd VARCHAR(500);
SET tableOneCount = (SELECT COUNT(*) FROM proj);
SET tableTwoCount = (SELECT COUNT(*) FROM proj2);
SET msg = tableOneCount + tableTwoCount;
Create table tempa(name varchar(50), counter integer);
Insert into tempa(name, counter) values ('counter1', tableOneCount);
Insert into tempa(name, counter) values ('counter2', tableTwoCount);
Insert into tempa(name, counter) values ('counter_all', msg);
SET strCmd=(SELECT * FROM tempa);
EXECUTE IMMEDIATE(strCmd);
drop table tempa;
END #
It should just count the 2 tables add them and then return a table with the results. Since I haven't figured out another way to do it I create a temp table and insert everything there to then just return a select statement. Somehow though this is not working since the select statement is running into an error.
I tried using
declare global temporary table session.tempa
(name varchar(50), counter integer)
on commit preserve rows not logged;
but that gives me the error, that the amount of rows and variables are not matching (SQL0117N)
Any idea on how to get this to work?
You last statement (dynamic query formation is not correct) throwing error which should be like below
SET strCmd="SELECT * FROM tempa";
EXECUTE IMMEDIATE(strCmd);
Though you don't need to form a dynamic query statement here at all. You can just return the select like SELECT * FROM tempa.
Again your procedure can be shorten like
CREATE or replace PROCEDURE TESTx()
BEGIN
DECLARE tableOneCount INTEGER;
SET tableOneCount = (SELECT COUNT(*) FROM proj) + (SELECT COUNT(*) FROM proj2);
select 'counter1', count(*) from proj
union all
select 'counter2', COUNT(*) FROM proj2
union all
select 'counter_all', tableOneCount from dual
END #

SQL Server 2008 Splitting string variable number of token per line

I have a fairly simple requirement -I have a table with the following (relevant) structure.
with cte as(
select 1 id,'AA,AB,AC,AD' names union all
select 2,'BA,BB' union all
select 3,'CA,CB,CC,CD,CE' union all
select 4,'DA,DB,DC'
)
i would like to create a select statement which will split each "names" column into multiple rows.
For example the first row should produce
1,'AA'
1,'AB'
1,'AC'
1,'AD'
Can we do it using only SQL. This is failry easy to do in Oracle.
You can do it in one query with no custom defined functions if you leverage XML:
WITH cte AS( /*your data*/
SELECT 1 id,'AA,AB,AC,AD' names UNION ALL
SELECT 2,'BA,BB' UNION ALL
SELECT 3,'CA,CB,CC,CD,CE' UNION ALL
SELECT 4,'DA,DB,DC'
)
, xmlData AS ( /*make into xml*/
SELECT id, cast('<root><x>'+replace(names,',','</x><x>')+'</x></root>' as xml) AS theXML
FROM cte
)
SELECT id, x.value('.','varchar(100)') /*split up*/
FROM xmlData
CROSS APPLY xmlData.theXML.nodes('//x') AS func(x)
You can create a split function that returns a table, then select from that table.
/***************************************************************************
**
** Function: split
** In: #ipRowData - The delimited list of items to split.
** In: #ipSplitOn - The delimiter which separates the items in #rowData.
** Returns: A table object containing the split items. The table object
** will have an ID and Data column, where ID is the number of the item
** in the original list and Data is the value of the item.
**
** Description:
** Splits a delimited set of items and returns them
** as a table object.
***************************************************************************/
CREATE FUNCTION [dbo].[split]
(
#ipRowData NVARCHAR(4000),
#ipSplitOn NVARCHAR(5)
)
RETURNS #rtnValue table
(
ID INT identity(1,1),
Data NVARCHAR(100)
)
AS
BEGIN
DECLARE
#cnt INT
Set #cnt = 1
WHILE (Charindex(#ipSplitOn,#ipRowData)>0)
BEGIN
INSERT INTO #rtnValue
( data )
SELECT Data = ltrim(rtrim(Substring(#ipRowData,1,Charindex(#ipSplitOn,#ipRowData)-1)))
SET #ipRowData = Substring(#ipRowData,Charindex(#ipSplitOn,#ipRowData)+1,len(#ipRowData))
SET #cnt = #cnt + 1
END
INSERT INTO #rtnValue (data)
SELECT DATA = ltrim(rtrim(#ipRowData))
RETURN
END
GO
Sample Usage:
select 1,data from [dbo].split('AA,AB,AC,AD', ',');
Output:
(No column name) data
1 AA
1 AB
1 AC
1 AD