Update statement SQL with CTE - sql

I have a common table expression that I am using trying to use as an update statement. The only reason for the CTE is so I can use a where clause to filter by CredCount. I would like to use that where clause to update only records that match in this case CredCount of 2. However, I am having trouble with the update part of the query.
Members_id
Credentials
CredCount
members_amountdue
1
CMA, CPR
2
0
2
CMA, CPR
2
0
3
CMA, CPR
2
0
Here is the query for that
WITH CTE AS (
SELECT members_id, members_amountdue, [Credentials], LEN([Credentials]) - LEN(REPLACE([Credentials], ',', '')) + 1 AS CredCount
FROM (
SELECT DISTINCT mem1.members_id, mem1.members_amountdue,
STUFF(
(SELECT DISTINCT ', ' + credentials_code
FROM members AS mem JOIN
members_credentials AS mc ON mc.members_id = mem.members_id JOIN
credentials AS c ON c.credentials_id = mc.credentials_id
WHERE mem.[members_id] = mem1.[members_id]
FOR XML PATH ('')), 1, 1, '') AS [Credentials]
FROM members AS mem1 JOIN
members_status as ms on ms.members_status_id = mem1.members_status_id
) AS derived),
CTE2 AS ( SELECT members_id
FROM members)
SELECT CTE.members_id, CTE.Credentials, CTE.CredCount, (CTE.members_amountdue + 25) as NewPriceTotal
FROM CTE JOIN
CTE2 ON CTE.members_id = CTE2.members_id
WHERE CTE.CredCount = 2
With the update statement I was looking at an example provided here at Update records in table from CTE so I added the update statement to the bottom of the query
WITH CTE AS (
SELECT members_id, members_amountdue, [Credentials], LEN([Credentials]) - LEN(REPLACE([Credentials], ',', '')) + 1 AS CredCount
FROM (
SELECT DISTINCT mem1.members_id, mem1.members_amountdue,
STUFF(
(SELECT DISTINCT ', ' + credentials_code
FROM members AS mem JOIN
members_credentials AS mc ON mc.members_id = mem.members_id JOIN
credentials AS c ON c.credentials_id = mc.credentials_id
WHERE mem.[members_id] = mem1.[members_id]
FOR XML PATH ('')), 1, 1, '') AS [Credentials]
FROM members AS mem1 JOIN
members_status as ms on ms.members_status_id = mem1.members_status_id
) AS derived),
CTE2 AS ( SELECT members_id
FROM members)
SELECT CTE.members_id, CTE.Credentials, CTE.CredCount, (CTE.members_amountdue + 25) as NewPriceTotal
FROM CTE JOIN
CTE2 ON CTE.members_id = CTE2.members_id
WHERE CTE.CredCount = 2
UPDATE members
set members_amountdue = NewPriceTotal
When I add the update statement I get an error for invalid column name for 'NewPriceTotal'. I know I need the column to match in order for the update to work but I'm not sure why it's invalid.
Members_id
Credentials
CredCount
NewPriceTotal
1
CMA, CPR
2
25
2
CMA, CPR
2
25
3
CMA, CPR
2
25
I would like for the NewPriceTotal to be set at the members_amountdue from the members table but I'm not sure where I made the wrong turn at. Any help, comments or feedback is greatly appreciated.

Try this:
....
CTE2 AS (
SELECT members_id
FROM members
), CTE3 AS (
SELECT CTE.members_id, CTE.Credentials, CTE.CredCount,
CTE.members_amountdue,
(CTE.members_amountdue + 25) as NewPriceTotal
FROM CTE JOIN CTE2 ON CTE.members_id = CTE2.members_id
WHERE CTE.CredCount = 2)
UPDATE CTE3
SET members_amountdue = NewPriceTotal

Related

How to get Email ID(one value) for each ID for 1st table and then display Email Name from 2nd table as comma Separated in SQL Server 2012?

What i have tried
Results wanted like thisFrom One table , for each ID there can be multiple email id's based on some condition Ex
ID EmailID's
1 Mike.Foster#Mail.com
1 lilly.Foster#Mail.com
2 Michel.Josh#Mail.com
2 Nash.Ted#Mail.com
I have to get email Name from these Ids from another table, something like this
Output i Need
Email_Name
Foster.Mike,Foster.Lilly
Josh.Michel,Ted.Nash
This is what i tried.
SELECT User_Email =
STUFF((SELECT DISTINCT ', ' + User_Email
FROM table1 b
WHERE b.Component_ID= a.Component_ID
and [Role] ='Team Lead' and Functional_Group ='Product'
FOR XML PATH('')), 1, 2, '')
FROM [WFS].table1 a
GROUP BY table1
Now another table i want Email Names
Select EmailNamefrom Table2 where EmailIDs IN ( 'code for Email')
Table1 schema
ID Component_ID EmailIDs Role Functional_Group
1 1 Mike.Foster#Mail.com Team Lead Product
2 1 lilly.Foster#Mail.com Team Lead Product
3 2 Michel.Josh#Mail.com Team Lead Product
4 2 Nash.Ted#Mail.com Team Lead Product
Table 2 schema
ID EmailIDs EmailName
1 Mike.Foster#Mail.com Foster.Mike
2 lilly.Foster#Mail.com Foster.Lilly
Any suggestions are welcome.Thanks in advance
Disregard this answer as I found out that GROUP_CONCAT() is a MySQL specific function, which means it won't work in SQL Server, however, I'll let it stay for future references.
SELECT
GROUP_CONCAT(EmailName SEPARATOR ', ') as name
FROM
table1
INNER JOIN table2 ON table1.EmailIDs=table2.EmailIDs
WHERE
table1.EmailIDs=table2.EmailIDs
GROUP BY
table1.Component_ID
Output:
Foster.Mike, Foster.Lilly
Ted.Nash, Josh.Michel
Working SQL fiddle
Docs: https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group-concat
You need CTE with STUFF() :
WITH t AS (
SELECT t1.*, t2.emailname
FROM table1 t1 INNER JOIN
table2 t2
ON t2.emailids = t1.emailids
)
SELECT id, STUFF ( (SELECT DISTINCT ','+t1.emailname
FROM t t1
WHERE t1.id = t.id
FOR XML PATH ('')
), 1, 1, ''
) AS Email_Name
FROM t
GROUP BY id;
You were actually close but your SQL doesn't match your schema. This one works as you want:
SELECT Email_Name =
STUFF((SELECT DISTINCT ', ' + EmailIDs
FROM table1 b
WHERE b.Component_ID= a.Component_ID
and [Role] ='Team Lead' and Functional_Group ='Product'
FOR XML PATH('')), 1, 2, '')
FROM table1 a
GROUP BY a.Component_ID;
EDIT: I didn't understand what you are asking exactly. Might this be what you meant?
SELECT STUFF((SELECT ', ' + EmailName
FROM Table2 where EmailIDs IN ( SELECT EmailIDs
FROM table1
WHERE [Role] ='Team Lead' and Functional_Group ='Product')
FOR XML PATH('')), 1, 2, '')
Or you meant this:
SELECT DISTINCT Component_ID, emailNames
FROM table1
CROSS APPLY (SELECT STUFF((SELECT ', '+t2.EmailName
FROM table2 t2
INNER JOIN TABLE1 t1 ON t1.EmailIDs = t2.EmailIDs
WHERE t1.Component_ID = Table1.Component_ID
FOR XML PATH('')), 1, 2, '')
) t(EmailNames)
WHERE [Role] ='Team Lead' and Functional_Group ='Product'
Here is SQLFiddle Demo

sql - Update more rows than I expected

I'm trying to update a part of my table. If I do a select statement, I find 17 ocurrences, but when I update it, it updates 997 ocurrences. I only want to update the 17 ocurrences. This is my code:
update proc_try k set detail = (
select jobs from
(
with
a ( nameHost ) as (
select b.nameHost
from definition a ,schema.nodes b
where b.nameHost = a.idNode or b.nodeid=a.idNode
and nodetype not like 'R'
group by b.nameHost
having sum(1 + lengthb(nameJob)) - 1 > 4000
)
select nameHost, 'TOOLONG' as jobs
from a
UNION ALL
select p.nameHost, listagg(p.nameJob,',') within group (order by p.nameJob) as jobs
from
(
select distinct b.nameJob, a.nameHost
from definition b
right join schema.nodes a
on b.idNode in (a.nodeid,a.nameHost) and
b.application not like '#NOTINCLUDE'
where a.nameHost not in (select * from a) and nodetype not like 'R'
--b.application not like '#NOTINCLUDE'
) p
group by p.nameHost) random
where k.nameHost=random.nameHost);
Could you help me please?
You can generally convert a complex update into a merge:
merge into proc_try k
using
( select jobs
from ( with a(namehost) as
( select b.namehost
from definition a
join schema.nodes b
on b.namehost = a.idnode
or (b.nodeid = a.idnode and nodetype <> 'R')
group by b.namehost
having sum(1 + lengthb(namejob)) - 1 > 4000 )
select namehost
, 'TOOLONG' as jobs
from a
union all
select p.namehost
, listagg(p.namejob, ',') within group(order by p.namejob) as jobs
from ( select distinct
b.namejob, a.namehost
from schema.nodes a
left join definition b
on b.idnode in (a.nodeid, a.namehost)
and b.application not like '#NOTINCLUDE'
where a.namehost not in (select * from a)
and nodetype not like 'R'
) p
group by p.namehost
) random
) new_jobs
on (k.namehost = new_jobs.namehost)
when matched then update set k.detail = new_jobs.jobs;
This is untested as I don't have your tables or sample data.
Edit: Looks like we can simplify it a bit, to this:
merge into proc_try k
using
( with overlength (namehost) as
( select n.namehost
from definition d
join schema.nodes n
on n.namehost = d.idnode
or (n.nodeid = d.idnode and nodetype <> 'R')
group by n.namehost
having sum(1 + lengthb(n.namejob)) - 1 > 4000 )
select o.namehost, 'TOOLONG' as jobs
from overlength o
union all
select sd.namehost
, listagg(sd.namejob, ',') within group(order by sd.namejob) as jobs
from ( select distinct d.namejob, n.namehost
from schema.nodes n
left join definition d
on d.idnode in (n.nodeid, n.namehost)
and d.application not like '#NOTINCLUDE'
where n.namehost not in (select o.namehost from overlength o)
and n.nodetype not like 'R'
) sd
group by sd.namehost
) new_jobs
on (new_jobs.namehost = k.namehost)
when matched then update set k.detail = new_jobs.jobs;
I still can't see what
sum(1 + lengthb(namejob)) - 1
is meant to do, though. It looks like that could be simplified to
sum(lengthb(namejob))

Create view with with statement

How to create view with a with statement?
I'm getting on error on it:
WITH temp as (
select uu.email, u.logintime, u.region, p.id as panelid, p.panelname, p.numberofdownloads, dimensionType + ' (' + dimensionValue + ')' as filter
from stat_users u
left join stat_panels p
on u.id=p.sessionid
left join stat_filters f
on p.id=f.panelid
left join users uu
on uu.id=u.userid
where uu.Organization = 'name' AND
year(logintime) between 2015 and 2017
and panelname is not null
)
CREATE VIEW final as(
select aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads as downloads, case when len(aa.filters) > 0 then left(aa.filters, len(aa.filters)-1) else '' end as filters
from (
Select distinct a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
Select b.filter + ', ' AS [text()]
From temp b
Where b.panelid=a.panelid
ORDER BY b.panelid
For XML PATH ('')
) filters
from temp a
) aa
)
I'm getting such error :
> Incorrect syntax near the keyword 'CREATE'. 'CREATE VIEW' must be the
> first statement in a query batch.
So, I need just to use Create view using select which based on WITH statement on Sql server 2014
Yes always the CREATE has to be the first statement in a query batch
CREATE VIEW vFinal AS
WITH Temp AS (
SELECT uu.email, u.logintime, u.region, p.id AS panelid, p.panelname, p.numberofdownloads, dimensionType + ' (' + dimensionValue + ')' AS Filter
FROM stat_users u
LEFT JOIN stat_panels p ON u.id=p.sessionid
LEFT JOIN stat_filters f ON p.id=f.panelid
LEFT JOIN users uu ON uu.id=u.userid
WHERE uu.Organization = 'name' AND
YEAR(logintime) BETWEEN 2015 AND 2017
AND panelname IS NOT NULL
)
SELECT aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads AS downloads, CASE WHEN LEN(aa.filters) > 0 THEN LEFT(aa.filters, LEN(aa.filters)-1) else '' end as filters
FROM (
SELECT DISTINCT a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
SELECT b.filter + ', ' AS [text()]
FROM temp b
WHERE b.panelid=a.panelid
ORDER BY b.panelid
FOR XML PATH ('')
) filters
FROM temp a
) aa
GO
Syntax to create a view table using CTE
CREATE VIEW View_Name AS
WITH CTE_Name (Columns) AS (SELECT QUERY)
SELECT QUERY using the CTE Table
GO
The with clause is an optional prefix for select:
WITH query_name (column_name1, ...) AS
(SELECT ...)
SELECT ...
This is also true when with is used in a view:
CREATE VIEW ...
WITH ...
SELECT ...
;
See also: http://modern-sql.com/feature/with
CREATE or replace VIEW final as
select aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads as downloads, case when len(aa.filters) > 0 then left(aa.filters, len(aa.filters)-1) else '' end as filters
from (
Select distinct a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
Select b.filter + ', ' AS [text()]
From temp b
Where b.panelid=a.panelid
ORDER BY b.panelid
For XML PATH ('')
) filters
from temp a )

How do you get the last record generated in a recursive

I am using recursive in sql 2014 in below code.
WITH products AS
(
SELECT
prd.productID,
prd.MainproductID,
prc.Price,Level = 0,
Row_ID = CAST(ROW_NUMBER() OVER (ORDER BY prd.productID) AS VARCHAR(MAX)),
Level2 = CAST(prd.productID AS VarChar(Max))
FROM
PrdTable prd
INNER JOIN prd_priceList (NOLOCK) prc ON prd.productID= prc.productID
WHERE prd.MainproductID IS NULL
UNION ALL
SELECT
prd.productID,
prd.MainproductID,
prc.Price,Level +1,
prcRec.Row_ID + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY prd.MainproductID ORDER BY prd.productID) AS VARCHAR(MAX)),
Level2 = CAST(prcRec.productID AS VarChar(Max)) + ', ' + prcRec.Level2
FROM
products prcRec
INNER JOIN PrdTable prd ON prcRec.productID= prd.MainproductID
INNER JOIN prd_priceList (NOLOCK) prc ON prd.productID= prc.productID
)
select
productID ,
MainproductID ,
Level,
Row_ID,
Level2
from prodproductsucts
And this return like result in attachment screenshot. I want only select bottom line of each level.If doesn't have child then will select its. But if has child then will go to latest level and pick latest one. I alsa paint yellow rows which i need to select in screenshot.
If I understand your requirements...
In the final query just add the following WHERE
... Where productID not in (Select Distinct ISNULL(MainProductID,-999) From products)

trying to concatenate a column into a comma delimited list

i have 3 tables, 1 for products and one for categories the products are assigned to. what IM trying to do is concatenate the column called stCategoryName to a single column in a comma delimited list.
Basically I have the products table containing the primary key for each product and im trying to figure out how to concatenate all the stcategoryName column next to each product so i can have a simplified return
what im trying to get is the following.
stProductID stCategoryName
123 category1,category2,category3
SELECT
dbo.StoreItemTracking.StCategoryID,
dbo.StoreItemTracking.StProductID,
dbo.StoreItemTracking.viewOrder,
dbo.StoreCategories.StCategoryName,
dbo.Store_Products.PartNumber
FROM
dbo.StoreItemTracking
INNER JOIN dbo.StoreCategories
ON dbo.StoreItemTracking.StCategoryID = dbo.StoreCategories.StCategoryID
INNER JOIN dbo.Store_Products
ON dbo.StoreItemTracking.StProductID = dbo.Store_Products.ID
Im stuck as to how to concatenate a column where the query contains 3 tables to select from.
any help greatly appreciated
Look at using coalesce to turn category into a CSV:
See example:
DECLARE #EmployeeList varchar(100)
SELECT #EmployeeList = COALESCE(#EmployeeList + ', ', '')
+ CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT #EmployeeList
You can also use CTE's or Subqueries. See:
http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=createacommadelimitedlist
Another nice and easy example:
http://www.codeproject.com/Articles/21082/Concatenate-Field-Values-in-One-String-Using-CTE-i
This:
FId FName
--- ----
2 A
4 B
5 C
6 D
8 E
with:
;WITH ABC (FId, FName) AS
(
SELECT 1, CAST('' AS VARCHAR(8000))
UNION ALL
SELECT B.FId + 1, B.FName + A.FName + ', '
FROM (And the above query will return
SELECT Row_Number() OVER (ORDER BY FId) AS RN, FName FROM tblTest) A
INNER JOIN ABC B ON A.RN = B.FId
)
SELECT TOP 1 FName FROM ABC ORDER BY FId DESC
becomes:
FName
----------------------------
A, B, C, D, E,
Don't understand how your products and categories are connected but in general I do like this to create comma separated lists.
SELECT table1.Id
,Csv
FROM table1
CROSS APPLY (
-- Double select so we can have an alias for the csv column
SELECT (SELECT ',' + table2.Name
FROM table2
WHERE table2.Id = table1.Id
FOR XML PATH('')
) AS RawCsv
) AS CA1
CROSS APPLY (
-- Trim the first comma
SELECT RIGHT(RawCsv, LEN(RawCsv) - 1) AS Csv
) AS CA2