CTE and closing semi colons - sql

I'm trying to write a recursive CTE that references another CTE written before it.
The first cte nodes I've closed-off with a semicolon before writing the recursive Hierarchy cte:
WITH nodes(node, node_name, parent, parent_name) AS
(
SELECT
Grp.PermissionGroupID as node,
Grp.GroupName as node_name,
GrpLink.ParentPermissionGroupID as parent,
ParentGrp.GroupName as parent_name
FROM _CCC_Permission_Group Grp
LEFT JOIN _CCC_Permission_GroupGroup GrpLink
on Grp.PermissionGroupID = GrpLink.ChildPermissionGroupID
LEFT JOIN _CCC_Permission_Group ParentGrp
on GrpLink.ParentPermissionGroupID = ParentGrp.PermissionGroupID
);
WITH Hierarchy(node, node_name, depth, parent, parent_name)
AS
(
SELECT
node,
node_name,
0,
parent,
parent_name
FROM nodes as FirstDepth
WHERE parent IS NULL
UNION ALL
SELECT
NextDepth.node,
NextDepth.node_name,
Parent.depth + 1,
Parent.parent,
Parent.parent_name
FROM nodes as NextDepth
INNER JOIN Hierarchy as Parent
on NextDepth.parent = Parent.parent
)
SELECT *
FROM Hierarchy
OPTION (MAXRECURSION 32767)
I get the error:
Msg 102, Level 15, State 1, Line 17 Incorrect syntax near ';'.
When I remove the semicolon, I get the errors:
Msg 156, Level 15, State 1, Line 19 Incorrect syntax near the keyword
'WITH'.
Msg 319, Level 15, State 1, Line 19 Incorrect syntax near the
keyword 'with'. If this statement is a common table expression, an
xmlnamespaces clause or a change tracking context clause, the previous
statement must be terminated with a semicolon.
...I don't write CTEs (let alone recursive ones) that often, so I'm not too sure how to resolve this apparent conflict with the ; placement.

A CTE needs only one WITH clause. You can create stacked CTE by just adding comma at the end of previous CTE followed by CTE name
;WITH nodes(node, node_name, parent, parent_name) AS
(
....
),Hierarchy(node, node_name, depth, parent, parent_name)
AS
(
..
)
SELECT *
FROM Hierarchy
OPTION (MAXRECURSION 32767)

You only use a closing semi-colon at the end of the statement. All the CTEs form a single statement. When using multiple CTEs in a single statement, separate each CTE using a comma.
WITH nodes(node, node_name, parent, parent_name) AS
...
), Hierarchy(node, node_name, depth, parent, parent_name) AS (
...
)
SELECT ...
OPTION (MAXRECURSION 32767);
Note the semi-colon at the end. You should get in to the habit of including this as in the future more statements will require it (e.g. the MERGE statement must be terminated using a semi-colon).

Related

Will unused CTE in a SQL statement be run

I have a question about CTEs. You can start of a sql statement by WITH and then you can construct one or multiple CTE queries, which you then in the end can make (in this case) a select on.
My question is: will all CTE queries be executed or only the ones who are being used?
E.g.
WITH cte_1
as (
Select * from table1
),
cte_2
as (
Select * from table2
)
Select * from cte_1
Will this mean that a select will be executed on table1 and table2?
To complete Master Gordon's answer (I dare) :
if you declare 2 cte, and use none of them, you also get that error message
with cte as (select 1/0 as val), cte2 as (select 1/0 as val)
select 1
Msg 422 Level 16 State 4 Line 2
Common table expression defined but not used.
But if you use at least one, the statement is accepted :
with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_divide_by_zero
Msg 8134 Level 16 State 1 Line 1
Divide by zero error encountered.
And if you select the other CTE, it proves that your unused CTE is never executed as no error occurs :
with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_legit
val
--------
it works
I get this message:
Msg 422 Level 16 State 4 Line 2
Common table expression defined but not used.
when running:
with cte as (select 1/0 as val)
select 1
Here is a db<>fiddle.

Incorrect syntax near ')' Error in the CTE

I wrote the following CTE (Common Table Expression)
WITH PRODUCTION_CTE(ShortProdNo,BoatRefNumber,ProdNo, CustomerPoNumber,LoadDate, Trailer, VeadaBuilding)
AS
(
SELECT
FBS.BoatNumber AS ShortProdNo,
UOD.BoatRefNumber AS BoatRefNumber,
FBS.ProdNo AS ProdNo,
UOD.CustomerPoNumber AS CustomerPoNumber,
FBS.Shipped AS LoadDate,
FBS.TruckNum AS Trailer,
(CASE
WHEN Rtrim(UOD.CustomerPoNumber)='VEADA-VS1' THEN 'Bldg10'
ELSE 'Bldg4'
END) AS VeadaBuilding
FROM SysproCompanyV.dbo.FlatBenningtonShipping as FBS
INNER JOIN SysproCompanyV.dbo.UsrOrderDetails as UOD
ON FBS.BoatNumber=UOD.BoatRefNumber)
I am getting the following Error from the above CTE:
Msg 102, Level 15, State 1, Line 17
Incorrect syntax near ')'.
I am not sure why it is happening as Inner Joins are allowed in the CTE, all the parenthesis are closed and the names are correctly declared.
You need to call the CTE (i.e. PRODUCTION_CTE) IMMEDIATE after declaration :
;with PRODUCTION_CTE as (
. . .
)
select pc.*
from PRODUCTION_CTE pc

Combining two CTEs with UNION causes an error

Getting the following error:
'Msg 156, Level 15, State 1, Line 53
Incorrect syntax near the keyword 'WITH'.
Msg 319, Level 15, State 1, Line 53
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.'
When running the CTE's separately it's fine. But when combining using a UNION.. then the error appears.
With cte1 as
(
select
.
.
.
Select
from
)
select
UNION
With cte2 as
(
Select
From
)
Select
from
In SQL Server, CTEs are attached to the outermost select. In other words, there is only one per query and all the definitions must come before the select.
So combine them into a single with:
with cte1 as (
select . . .
),
cte2 as (
select . . .
)
select . . .
from cte1 . . .
union
select . .
from cte2 . . .;

SQL Select with a function

I have the following SQL Statement :
SELECT
RTRIM(LTRIM(REPLACE(LAGKART.VARENUMMER,CHAR(2),''))) AS ItemNo,
RTRIM(LTRIM(REPLACE(LAGKART.SXSON,CHAR(2),''))) AS Season,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT1,CHAR(2),''))),'') AS Variant1,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT2,CHAR(2),''))),'') AS Variant2,
(SELECT *
FROM [dbo].[B2BGetSpringFinal] ( LAGKART.VARENUMMER,
LAGKART.VARIANT1,
LAGKART.VARIANT2
)) AS SpringAvailable
FROM
LAGKART
But I get this error :
Msg 170, Level 15, State 1, Line 8
Incorrect syntax near '.'.
But if I call the function with fixed values :
SELECT
RTRIM(LTRIM(REPLACE(LAGKART.VARENUMMER,CHAR(2),''))) AS ItemNo,
RTRIM(LTRIM(REPLACE(LAGKART.SXSON,CHAR(2),''))) AS Season,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT1,CHAR(2),''))),'') AS Variant1,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT2,CHAR(2),''))),'') AS Variant2,
(SELECT *
FROM [dbo].[B2BGetSpringFinal] ( '6261',
'Black',
'S'
)) AS SpringAvailable
FROM
LAGKART
I get the desired result.
Any ideas?
Br
Mads
In SQL Server 2000, Only constants and #local_variables can be passed to table-valued functions. In SQL 2005 and greater this was fixed. You could try using a scalar function to get the SpringAvailable column value instead, or look at upgrading to a newer SQL Server version.
if your server supports CTEs you could try this one:
WITH a as (
SELECT VARENUMMER,
RTRIM(LTRIM(REPLACE(LAGKART.VARENUMMER,CHAR(2),''))) AS ItemNo,
RTRIM(LTRIM(REPLACE(LAGKART.SXSON,CHAR(2),''))) AS Season,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT1,CHAR(2),''))),'') AS Variant1,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT2,CHAR(2),''))),'') AS Variant2,
FROM LAGKART
)
select *,
(SELECT * FROM [dbo].[B2BGetSpringFinal] ( a.VARENUMMER,
a.VARIANT1,
a.VARIANT2
)) AS SpringAvailable
from a ;
You can use APPLY (CROSS or OUTER) to pass column(s) value(s) as arguments to a function:
SELECT RTRIM(LTRIM(REPLACE(LAGKART.VARENUMMER,CHAR(2),''))) AS ItemNo,
RTRIM(LTRIM(REPLACE(LAGKART.SXSON,CHAR(2),''))) AS Season,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT1,CHAR(2),''))),'') AS Variant1,
ISNULL(RTRIM(LTRIM(REPLACE(LAGKART.VARIANT2,CHAR(2),''))),'') AS Variant2,
SpringAvailable.*
FROM LAGKART
CROSS APPLY
(
SELECT *
FROM [dbo].[B2BGetSpringFinal] ( LAGKART.VARENUMMER, LAGKART.VARIANT1,LAGKART.VARIANT2 )
) AS SpringAvailable

Select From CTE using AS? SQL Server 2008

I'm trying to convert a PostgreSQL into SQL Server. But this query doesn't work.
What am I doing wrong? I tried to add a semicolon before WITH but no luck.
SELECT
member_a AS you, member_b AS mightknow, shared_connection,
CASE
WHEN (n1.member_job_country = n2.member_job_country AND n1.member_job_country = n3.member_job_country) THEN 'country in common'
WHEN (n1.member_unvan_id = n2.member_unvan_id AND n1.member_unvan_id = n3.member_unvan_id) THEN 'unvan in common'
ELSE 'nothing in common'
END AS reason
FROM (
WITH transitive_closure(member_a, member_b, distance, path_string, direct_connection) AS
(SELECT
member_a, member_b, 1 AS distance,
CAST(member_a as varchar(MAX)) + '.' + CAST(member_b as varchar(MAX)) + '.' AS path_string,
member_b AS direct_connection
FROM Member_Contact_Edges
WHERE member_a = 45046 -- set the starting node
UNION ALL
SELECT
tc.member_a, e.member_b, tc.distance + 1,
CAST(tc.path_string as varchar(MAX)) + CAST(e.member_b as varchar(MAX)) + '.' AS path_string,
tc.direct_connection
FROM Member_Contact_Edges AS e
JOIN transitive_closure AS tc ON e.member_a = tc.member_b
WHERE tc.path_string NOT LIKE '%' + CAST(e.member_b as varchar(MAX)) + '.%'
AND tc.distance < 2
)
SELECT
member_a, member_b,direct_connection AS shared_connection
FROM transitive_closure
WHERE distance = 2
) AS youmightknow
LEFT JOIN Members AS n1 ON youmightknow.member_a = n1.memberID
LEFT JOIN Members AS n2 ON youmightknow.member_b = n2.memberID
LEFT JOIN Members AS n3 ON youmightknow.shared_connection = n3.memberID
WHERE (n1.member_job_country = n2.member_job_country
AND n1.member_job_country = n3.member_job_country)
OR (n1.member_unvan_id = n2.member_unvan_id
AND n1.member_unvan_id = n3.member_unvan_id);
Error I get:
Msg 156, Level 15, State 1, Line 11
Incorrect syntax near the keyword 'WITH'.
Msg 319, Level 15, State 1, Line 11
Incorrect syntax near the keyword 'with'. If this statement is a
common table expression, an
xmlnamespaces clause or a change
tracking context clause, the previous
statement must be terminated with a
semicolon.
Msg 102, Level 15, State 1, Line 34
Incorrect syntax near ')'.
Here is the reference; Graphs in the Database - SQL Meets Social Networks - Look at the facebook suggestion part at the bottom of the article.
Thanks in advance
The CTE declaration needs to go at the top. You can also have multiple CTEs declared and joined by commas rather than mixing CTEs and derived tables.
Try
;WITH
/*First CTE declaration*/
transitive_closure(member_a, member_b, distance, path_string, direct_connection)
AS
(
...
),
/*Second CTE declaration*/
youmightknow AS
(
SELECT member_a, member_b,direct_connection AS shared_connection
FROM transitive_closure
WHERE distance = 2
)
SELECT member_a AS you,
...
FROM youmightknow
Move your CTE definition to the beginning of your SQL statement. The keyword WITH appears once at the beginning of your statement to introduce one or more CTEs, which may then be referred to in the following SQL. Take a look at this CTE example, it will clear it up for you.