Creating a table from a prior WITH clause in BigQuery - sql

WITH LAYER AS (
SELECT
SPLIT(de_nest, '|')[OFFSET(1)] AS product,
....
FROM `table`,
UNNEST(SPLIT(LOWER(REPLACE(variable, '^', '-')), '-')) AS de_nest
)
-- Filter out empty products
CREATE OR REPLACE TABLE `newtable` AS
SELECT * FROM LAYER WHERE product is NOT NULL
This leads me to the following error.
Syntax error: Expected "(" or "," or keyword SELECT but got keyword CREATE at [25:1]
But I cannot seem to find a sensible way of resolving this. My first workload is doing the un-nesting of the first table and the second is doing some filtering on those columns generated from the un-nesting process.

You should try to put the CTE declaration after the CREATE statement:
CREATE OR REPLACE TABLE `new_table` AS
WITH layer AS ...
EDIT: a complete example
CREATE OR REPLACE TABLE
`your_project.your_dataset.your_table` AS
WITH
layer1 AS (
SELECT
'this is my CTE' AS txt),
another_cte AS (
SELECT
txt,
SPLIT(txt, ' ') AS my_array
FROM
layer1)
SELECT
*
FROM
another_cte
Creates the following table

Related

Checking if field contains multiple string in sql server

I am working on a sql database which will provide with data some grid. The grid will enable filtering, sorting and paging but also there is a strict requirement that users can enter free text to a text input above the grid for example
'Engine 1001 Requi' and that the result will contain only rows which in some columns contain all the pieces of the text. So one column may contain Engine, other column may contain 1001 and some other will contain Requi.
I created a technical column (let's call it myTechnicalColumn) in the table (let's call it myTable) which will be updated each time someone inserts or updates a row and it will contain all the values of all the columns combined and separated with space.
Now to use it with entity framework I decided to use a table valued function which accepts one parameter #searchQuery and it will handle it like this:
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS #Result TABLE
( ... here come columns )
AS
BEGIN
DECLARE #searchToken TokenType
INSERT INTO #searchToken(token) SELECT value FROM STRING_SPLIT(#searchText,' ')
DECLARE #searchTextLength INT
SET #searchTextLength = (SELECT COUNT(*) FROM #searchToken)
INSERT INTO #Result
SELECT
... here come columns
FROM myTable
WHERE (SELECT COUNT(*) FROM #searchToken WHERE CHARINDEX(token, myTechnicalColumn) > 0) = #searchTextLength
RETURN;
END
Of course the solution works fine but it's kinda slow. Any hints how to improve its efficiency?
You can use an inline Table Valued Function, which should be quite a lot faster.
This would be a direct translation of your current code
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS TABLE
AS RETURN
(
WITH searchText AS (
SELECT value token
FROM STRING_SPLIT(#searchText,' ') s(token)
)
SELECT
... here come columns
FROM myTable t
WHERE (
SELECT COUNT(*)
FROM searchText
WHERE CHARINDEX(s.token, t.myTechnicalColumn) > 0
) = (SELECT COUNT(*) FROM searchText)
);
GO
You are using a form of query called Relational Division Without Remainder and there are other ways to cut this cake:
CREATE FUNCTION myFunctionName(#searchText NVARCHAR(MAX))
RETURNS TABLE
AS RETURN
(
WITH searchText AS (
SELECT value token
FROM STRING_SPLIT(#searchText,' ') s(token)
)
SELECT
... here come columns
FROM myTable t
WHERE NOT EXISTS (
SELECT 1
FROM searchText
WHERE CHARINDEX(s.token, t.myTechnicalColumn) = 0
)
);
GO
This may be faster or slower depending on a number of factors, you need to test.
Since there is no data to test, i am not sure if the following will solve your issue:
-- Replace the last INSERT portion
INSERT INTO #Result
SELECT
... here come columns
FROM myTable T
JOIN #searchToken S ON CHARINDEX(S.token, T.myTechnicalColumn) > 0

multiple selects from a function into a temp table

I have a function helper_function which I want to reuse
Passing a parameter to another function f_union_helper_functions where a string id_string with ids is passed
Split this string and iterate through all ids
calling the function and adding result to a temp table
return select from this table
Pseudo code:
create function f_union_helper_functions
(
#id_string varchar,
...
return table as
return
(
...
foreach id in #id_string
begin
select * from helper_function(id) into #tmp
end
select #tmp
)
This code above is far from being complete/correct. I just want to combine the concepts of iterating and union into a temp table and return it. How can I achieve that?
Here is the way I solved it:
ALTER FUNCTION [dbo].[f_union_helper_functions]
(
#id_string NVARCHAR(1024)
)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM [dbo].[fnSplit](#id_string, ',') c CROSS APPLY [dbo].[helper_function](c.item)
)
If you got SQLServer >= 2016 you can use STRING_SPLIT instead of [fnSplit], which I got from here https://kishsharma.wordpress.com/2013/08/20/sql-server-user-defined-function-to-split-the-string-by-special-char/

MACRO to create a table in SQL

Hi everyone thanks so much for taking the time to read this.
I'd like to create a macro in Teradata that will create a table from another table based on specific parameters.
My original table consists of three columns patient_id, diagnosis_code and Date_of_birth
......
I'd like to build a macro that would allow me to specify a diagnosis code and it would then build the table consisting of data of all patients with that diagnosis code.
My current code looks like this
Create Macro All_pats (diag char) as (
create table pats as(
select *
from original_table
where diag = :diagnosis_code;)
with data primary index (patid);
I cant seem to get this to work - any tips?
Thanks once again
Your code has a semicolon in a wrong place and a missing closing bracket:
Create Macro All_pats (diag char) as (
create table pats as
(
select *
from original_table
where diag = :diagnosis_code
) with data primary index (patid);
);
Edit:
Passing multiple values as a delimited list is more complicated (unless you use Dynamic SQL in a Stored Procedure):
REPLACE MACRO All_lpats (diagnosis_codes VARCHAR( 1000)) AS
(
CREATE TABLE pats AS
(
SELECT *
FROM original_table AS t
JOIN TABLE (StrTok_Split_To_Table(1, :diagnosis_codes, ',')
RETURNS (outkey INTEGER,
tokennum INTEGER,
token VARCHAR(20) CHARACTER SET Unicode)
) AS dt
ON t.diag = dt.token
) WITH DATA PRIMARY INDEX (patid);
);
EXEC All_lpats('111,112,113');
As the name implies StrTok_Split_To_Table splits a delimited string into a table. You might need to adust the delimiter and the length of the resulting token.

Stored proc temporary table with parameters

Hello in a stored procedure, i create a temp-table filled with a select wich execute a function to return date recurrences.
The creation of my temp table looks like this :
BEGIN
insert into #tmp_recu
SELECT * FROM dbo.CrontabSchedule('0 0 * * *', '2017-2-1', '2017-2-28')
END
After creating this temp-table, i execute a query using this temp table like this :
Select * from mission
Cross Join #temp_recu
The problem is i'd like to remplace the '0 0 * * *' in my temp-table creation by a field from mission table (field named recurrence), so how could i do that?
Thanks !
EDIT
Actually, in my query, i'd like to call the function 'CrontabSchedule' and put in parameter a field from 'mission' table like this :
select * from mission m
cross join select * from dbo.CronTabSchedule(mission.reccurence,'2017-1-1','2017-1-31')
It works when i called the function like this
select * from dbo.CronTabSchedule('0 0 * * *','2017-1-1','2017-1-31')
But when i replace '0 0 * * *' by 'Mission.recurrence' (which contains the recurrence pattern of each mission), i have an error :
The multi-part identifier "Mission.recurrence" could not be bound.
CrontabSchedule code :
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER FUNCTION [dbo].[CrontabSchedule](#Expression [nvarchar](100), #Start[datetime], #End [datetime])
RETURNS TABLE (
[Occurrence] [datetime] NULL
) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [NCrontabSQL].[NContab.SQL.SqlCrontab].[GetOccurrences]
The function return a table with one column named 'Occurence' and contains à list of dates.
Pretty vague question here but I am assuming that CronTabSchedule must be a table valued function (hopefully an inline version but that is another topic). If I am correct you could use CROSS APPLY for this quite easily.
select *
from mission m
cross apply dbo.CronTabSchedule(m.reccurence,'2017-1-1','2017-1-31') cts

Dynamic SQL statement with nested selects

I have two tables, transforms and design_fields. transforms has a field called transforms, and design_fields has a field called transform. design_fields contains all of the transform rows, in which some are duplicates. transforms (table) transform (column) is what I am trying to populate with the transform values from design_fields.
I've been doing some of them by hand using the following queries.
Get list of design_fields transform that are not in transforms (table) transform (column):
select transform, COUNT(*) as trans_count
from design_fields
where transform not in (
select transform
from transforms
where transform is not null
)
group by transform
order by trans_count desc
Insert design_field transform into transforms (table) transform (column) + other stuff.
insert into transforms (field_id, transform_name, transform)
select field_id, logical_name, 'TRANSFORM NAME GOES HERE' as transform
from fields
where field_id in (
select field_id
from design_fields
where transform = 'TRANSFORM NAME GOES HERE'
)
Though this method works for the most part, there are over 600 rows that I would need to do this in. This is why I'd like to use a dynamic query to insert all the rows from that listing into the transforms table.
Here is what I have so far (disclaimer: I'm new to dynamic queries):
select 'insert into transforms (field_id, transform_name, transform)
select field_id, logical_name, ' +
(select distinct transform
from design_fields
where transform not in (
select transform
from transforms
where transform is not null ))
+ ' as transform
from fields
where field_id in (
select field_id
from design_fields
where transform = ' +
(select distinct transform
from design_fields
where transform not in (
select transform
from transforms
where transform is not null )) +
')'
This statement returns an error message saying that it returned more than 1 value. I understand why this is, I just don't know any other way to do this.
Any help, including pointers for future use of dynamic queries would be greatly appreciated!
What about using EXEC statement where you can make its parameter a string.
The exec statement would call a stored proc passing the insert parameters you want. for example:
Declare #SQL varchar(600);
Set #SQL = 'select * from yourTable';
EXEC(#SQL);