multi part indentifier could not be bound? - sql

I'm trying to use two tables in a stored procedure but am getting this error on the final line
''multi part identifier T.HireDate could not be bound''
I'm guessing its to do with the joining of the tables but am a little lost. Heres my code:
CREATE PROC spPayIncreaseCheck
AS
SELECT T.ID,FName,LName,HireDate,Payrate
FROM Assignment.dbo.Payments pay
join Assignment.dbo.Teachers T
ON pay.ID = T.ID
UPDATE Assignment.dbo.Payments
SET Payrate = 'High'
where T.HireDate < dateadd(year, -3, GETDATE())

Are you trying to update, or are you trying to select?
That is the wrong form for an update using a join in sql server.
The correct form would be like so:
update pay
set Payrate = 'High'
from Assignment.dbo.Payments pay
inner join Assignment.dbo.Teachers T
on pay.ID = T.ID
where T.HireDate < dateadd(year, -3, getdate());
Also, are you sure on pay.ID = T.ID is the correct join clause? Normally you would expect to see something like on pay.TeacherID = T.ID instead.

You are updating the Assignment.dbo.Payments table and in the WHERE condition you have a t.HireDate but t is not an alias that is used in the UPDATE statement.
In UPDATE you cannot use aliases.
Also, please notice that the SELECT and UPDATE statements are completely non-related inside your stored procedure. It is not clear though if you need them to be related.
You need an UPDATE FROM to do a set-based update:
UPDATE Assignment.dbo.Payments
SET Payrate = 'High'
FROM
SELECT T.ID,FName,LName,HireDate,Payrate
FROM Assignment.dbo.Payments pay
JOIN Assignment.dbo.Teachers T ON pay.ID = T.ID
WHERE T.HireDate < DATEADD(YEAR, -3, GETDATE())

The simplest way to achieve this, is using an exists clause to check if the payment record matches the teacher record:
update Assignment.dbo.Payments
set Payrate = 'High'
where exists ( select 1
from Assignment.dbo.Teachers
where Payments.ID = Teachers.ID
and Teachers.HireDate < dateadd(year, -3, getdate()) )

Related

SQL query running slowly - parameter sniffing

I have a simple query where I return a list of orders by date range. This query is used in a report which feeds it parameters(Site, From Date, and To Date).
ALTER PROCEDURE [dbo].[Z_N_ECOM_ORDER_STATUS_DATERANGE]
#Site VARCHAR(5),
#FromDate DATETIME,
#ToDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT
o.Company_Code,
o.Division_Code,
o.Control_Number,
RTRIM(o.Customer_Purchase_Order_Number) AS Shopify_Num,
CASE
WHEN p.PickTicket_Number IS NULL
THEN i.PickTicket_Number
ELSE p.PickTicket_Number
END PickTicket_Number,
i.Invoice_Number,
o.Date_Entered,
CASE
WHEN ph.packslip IS NULL AND i.invoice_number IS NULL
AND P.pickticket_number IS NULL
THEN 'Cancelled'
WHEN ph.packslip IS NULL AND i.invoice_number IS NULL
AND DATEADD(minute, 90, o.date_entered) > CURRENT_TIMESTAMP
THEN 'Not Entered Yet'
WHEN ph.packslip IS NULL
THEN 'SHIPPED & UPLOADED'
ELSE RTRIM (z.status)
END Accellos_Status,
b.UPS_Tracking_Number Tracking_Number
FROM
[JMNYC-AMTDB].[AMTPLUS].[dbo].Orders o (nolock)
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].PickTickets p (nolock) ON o.Company_Code = p.Company_Code
AND o.Division_Code = p.Division_Code
AND o.Control_Number = p.Control_Number
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].Invoices i (nolock) ON o.Company_Code = i.Company_Code
AND o.Division_Code = i.Division_Code
AND o.Control_Number = i.Control_Number
LEFT JOIN
[JMNYC-AMTDB].[AMTPLUS].[dbo].box b (nolock) ON o.Company_Code = b.Company_Code
AND o.Division_Code = b.Division_Code
AND i.PickTicket_Number = b.PickTicket_Number
LEFT JOIN
pickhead ph (nolock) ON p.PickTicket_Number = ph.packslip
LEFT JOIN
Z_Status z (nolock) ON ph.PROCSTEP = z.procstep
WHERE
o.Company_Code = LEFT(#Site, 2)
AND o.Division_Code = RIGHT(#Site, 3)
AND o.Customer_Number = 'ecom2x'
AND o.Date_Entered BETWEEN #FromDate AND DATEADD(dayofyear, 1, #ToDate)
ORDER BY
o.date_entered DESC
END
The problem with this query is that it takes way too long and the problem lines are
WHERE
o.Company_Code = LEFT(#Site, 2)
AND o.Division_Code = RIGHT(#Site, 3)
The format of the variable site is something like '09001' or '03001' where the left side is the company and the right side is the division
Because when I run this query with hard-coded values, it runs pretty much instantaneously. When I use the parameters, it takes minutes.
So I looked it up and I discovered about parameter sniffing. So I added the following line after the begin statement.
DECLARE #LocalSite VARCHAR(5) = CAST(#Site AS VARCHAR(5))
However, it still runs extremely slow.
My new where statement would be
WHERE
o.Customer_Number = 'ecom2x'
AND o.Date_Entered BETWEEN #FromDate AND DATEADD(dayofyear, 1, #ToDate)
AND ((#LocalSite = '00000') OR (O.Company_Code = LEFT(#LocalSite, 2) AND O.Division_Code = RIGHT(#LocalSite, 3)))
order by o.date_entered desc*
I also want the user to have the functionality of selecting all sites which will make the site variable be '00000' and thus it shouldn't run the company/division code check. This current where statement makes the query run very slow.
Does anyone know what I am doing wrong?
Can you try to avoid using LEFT() and RIGHT() by declaring few variables and assigning values to those variables and then using them in the SELECT statement?
a hint OPTIMIZED FOR UNKNOWN to avoid parameter sniffing:
option (OPTIMIZE FOR (#p1 UNKNOWN, #p2 UNKNOWN))
Where p1 and p2 those two variables mentioned above
I also want the user to have the functionality of selecting all sites
which will make the site variable be '00000' and thus it shouldn't run
the company/division code check. This current where statement makes
the query run very slow.
This can be optimized by replacing current SELECT with IF statement that uses two SELECTs. If value is 00000 just avoid to check on company and division, else run the same select but with those extra checks
Another striking thing is querying linked server objects with further join to local tables. Consider to split this into a separate step, for instance by storing data in temporary table (not a table variable!) as intermediate result. Then temp table to be joined with local objects. This can improve accuracy of query plan because of better estimates.
Did you try taking left and right values of#site parameter in two different variables and using those variables in SP.
For eg.
Declare #compcode as varchar(2)
Declare #divcode as varchar(3)
Set #compcode=LEFT(#Site, 2)
Set #divcode=RIGHT(#Site, 3)
Your where condition
WHERE
o.Company_Code = #compcode
AND o.Division_Code = #divcode

Query to update subscriber status to a list in salesforce marketing cloud

I have a data extension that I will be populating my subscriber information into (I have to do this due to my API set up). However, I want this information to be pasted to my publication list in salesforce. If people unsubscribe, a field in my data extension called 'Subscribed' will be updated to 'False' (and vica-versa). I want to set up a query to run everday that scans this data extension and updates all the false records to unsubscibed in my publication list. I built the query below, but I am getting an error that say
"Incorrect syntax near the keyword 'INNER'."
SELECT b.EMAIL_ADDRESS, 'Unsubscribed' AS Status
FROM Welcome b
WHERE b.Subscribed = 'False'
AND Date_Changed >= DATEADD(day, -1, GETDATE())
INNER JOIN _ListSubscribers a
ON a.EmailAddress = b.EMAIL_ADDRESS
WHERE a.ListID = '112'
Thanks!
Where clause always goes after joins
SELECT b.EMAIL_ADDRESS, 'Unsubscribed' AS Status
FROM Welcome b
INNER JOIN _ListSubscribers a ON a.EmailAddress = b.EMAIL_ADDRESS
WHERE b.Subscribed = 'False' and
a.ListID = '112' and
b.Date_Changed >= DATEADD(day, -1, GETDATE());

SSIS Lookup Transformation - SQL query not working

I have an SSIS package for deployment into a SQL Server 2012 SSISDB and it uses a Lookup transformation. I am using a result from a SQL query to perform the lookup comparison.
This does not work and I get all rows as "No matched".
The query is the following:
DECLARE #LastJobDate DATETIME
SELECT #LastJobDate = COALESCE(MIN(S.LastImportDate), DATEADD(DAY, -2, GETDATE()))
FROM Stations S INNER JOIN
Lines L ON S.ID_Line = L.ID_Line
WHERE L.Name LIKE 'lineType%' AND S.ImportData = 1 AND S.Active = 1
SELECT J.ID_Line, J.ID_Job, J.SerialNumber
FROM [Jobs] J INNER JOIN
[Lines] L ON J.ID_Line = L.ID_Line
WHERE L.Name LIKE 'lineType%'AND J.TimeStamp >= DATEADD(HOUR, -1, #LastJobDate)
By accident, I found that if I place a [SET NOCOUNT ON] at the beggining of the query, it will work.
DECLARE #LastJobDate DATETIME
SET NOCOUNT ON
SELECT #LastJobDate = COALESCE(MIN(S.LastImportDate), DATEADD(DAY, -2, GETDATE()))
FROM Stations S INNER JOIN
Lines L ON S.ID_Line = L.ID_Line
WHERE L.Name LIKE 'lineType%' AND S.ImportData = 1 AND S.Active = 1
SELECT J.ID_Line, J.ID_Job, J.SerialNumber
FROM [Jobs] J INNER JOIN
[Lines] L ON J.ID_Line = L.ID_Line
WHERE L.Name LIKE 'lineType%'AND J.TimeStamp >= DATEADD(HOUR, -1, #LastJobDate)
Am I missing something? Why this behavior?
Why this behavior?
An SSIS Lookup Component can only consider the first result returned by a multi-statement query such as yours.
When you don't have SET NOCOUNT ON, the first result returned by your query will be the message "1 row(s) affected" or something like that. The Lookup Component will not be able to look at the result set returned by the second half of your query.
This is why setting NOCOUNT ON fixes the problem. The "row(s) affected" message will not be returned by the first part of the query, and the only thing returned will be the resultset of the second part of the query, which the Lookup Component will then process.

SQL - replace returned data with other data

I am retrieving data using the SQL syntax below:
SELECT TOP 5 EventId, EventTime, DeviceName, Comment, Tenant, TenantName, Individual,
InetDb.dbo.Individuals.FirstName, InetDb.dbo.Individuals.LastName, InetDb.dbo.IndivImages.UserImage
FROM taclogdata.dbo.Event
LEFT JOIN InetDb.dbo.Tenants
ON taclogdata.dbo.Event.Tenant = InetDb.dbo.Tenants.TenantId
LEFT JOIN InetDb.dbo.Individuals
ON taclogdata.dbo.Event.Individual = InetDb.dbo.Individuals.IndivId
AND taclogdata.dbo.Event.Tenant = InetDb.dbo.Individuals.TenantNdx
LEFT JOIN InetDb.dbo.IndivImages
ON InetDb.dbo.Individuals.IndivId = InetDb.dbo.IndivImages.IndivNdx
AND InetDb.dbo.Individuals.TenantNdx = InetDb.dbo.IndivImages.TenantNdx
WHERE (taclogdata.dbo.Event.EventTime > DATEADD(hh, -3, GETDATE())AND taclogdata.dbo.Event.EventTime < GETDATE())
AND (taclogdata.dbo.Event.Comment='Reader entry' OR taclogdata.dbo.Event.Comment='Reader exit')
AND (taclogdata.dbo.Event.DeviceName = 'L9 1/4/1'
OR taclogdata.dbo.Event.DeviceName='L1 2/1/1-2 MainD'
OR taclogdata.dbo.Event.DeviceName='L1 2/1/3-4 MainD'
OR taclogdata.dbo.Event.DeviceName='L1 2/6/1-2 Stair'
OR taclogdata.dbo.Event.DeviceName='L1 2/2/1-2 FDT1')
ORDER BY taclogdata.dbo.Event.EventTime DESC
This code works fine, however I'm trying to simplify the results.
I'm trying to simplify what the query returns, by replacing the DeviceName value from e.g. L1 2/1/3-4 MainD to Main Door when the results are shown (not replace the actual data in the database)
How may I achieve this please ?
Thanks in advance,
J
try this use replace function
SELECT TOP 5 EventId, EventTime, replace(DeviceName,'L1 2/1/3-4 MainD','L1 2/1/3-4 Main Door') as DeviceName, Comment, Tenant, TenantName, Individual,
InetDb.dbo.Individuals.FirstName, InetDb.dbo.Individuals.LastName, InetDb.dbo.IndivImages.UserImage
FROM taclogdata.dbo.Event
LEFT JOIN InetDb.dbo.Tenants
ON taclogdata.dbo.Event.Tenant = InetDb.dbo.Tenants.TenantId
LEFT JOIN InetDb.dbo.Individuals
ON taclogdata.dbo.Event.Individual = InetDb.dbo.Individuals.IndivId
AND taclogdata.dbo.Event.Tenant = InetDb.dbo.Individuals.TenantNdx
LEFT JOIN InetDb.dbo.IndivImages
ON InetDb.dbo.Individuals.IndivId = InetDb.dbo.IndivImages.IndivNdx
AND InetDb.dbo.Individuals.TenantNdx = InetDb.dbo.IndivImages.TenantNdx
WHERE (taclogdata.dbo.Event.EventTime > DATEADD(hh, -3, GETDATE())AND taclogdata.dbo.Event.EventTime < GETDATE())
AND (taclogdata.dbo.Event.Comment='Reader entry' OR taclogdata.dbo.Event.Comment='Reader exit')
AND (taclogdata.dbo.Event.DeviceName = 'L9 1/4/1'
OR taclogdata.dbo.Event.DeviceName='L1 2/1/1-2 MainD'
OR taclogdata.dbo.Event.DeviceName='L1 2/1/3-4 MainD'
OR taclogdata.dbo.Event.DeviceName='L1 2/6/1-2 Stair'
OR taclogdata.dbo.Event.DeviceName='L1 2/2/1-2 FDT1')
ORDER BY taclogdata.dbo.Event.EventTime DESC
Here my suggestions:
If you can replace the data in your SELECT for example:
SELECT REPLACE(DeviceName,N'2/1/3-4 MainD',N'Main Door')
If you have many replacements, I would suggest to create a temporary table, join it and take the replacement from the temporary table.
The specific answer to your question is to use REPLACE() or a CASE statement. However, you should also change the WHERE clause to use IN and use table aliases so the code is easier to write and to read:
FROM taclogdata.dbo.Event e LEFT JOIN
InetDb.dbo.Tenants t
ON e.Tenant = t.TenantId LEFT JOIN
InetDb.dbo.Individuals i
ON e.Individual = i.IndivId AND e.Tenant = i.TenantNdx LEFT JOIN
InetDb.dbo.IndivImages ii
ON i.IndivId = ii.IndivNdx AND Ii.TenantNdx = ii.TenantNdx
WHERE (e.EventTime > DATEADD(hour, -3, GETDATE()) AND
e.EventTime < GETDATE()
) AND
e.Comment IN ('Reader entry', 'Reader exit') AND
e.DeviceName IN ('L9 1/4/1', 'L1 2/1/1-2 MainD', 'L1 2/1/3-4 MainD',
'L1 2/6/1-2 Stair', 'L1 2/2/1-2 FDT1'
)

Changing a SUM returned NULL to zero

I have a stored procedure as follows:
CREATE PROC [dbo].[Incidents]
(#SiteName varchar(200))
AS
SELECT
(
SELECT SUM(i.Logged)
FROM tbl_Sites s
INNER JOIN tbl_Incidents i
ON s.Location = i.Location
WHERE s.Sites = #SiteName AND i.[month] = DATEADD(mm, DATEDIFF(mm, 0, GetDate()) -1,0)
GROUP BY s.Sites
) AS LoggedIncidents
'tbl_Sites contains a list of reported on sites.
'tbl_Incidents contains a generated list of total incidents by site/date (monthly)
'If a site doesn't have any incidents that month it wont be listed.
The problem I'm having is that a site doesn't have any Incidents this month and as such i got a NULL value returned for that site when i run this proc, but i need to have a zero/0 returned to be used within a chart in SSRS.
I've tried using coalesce and isnull to no avail.
SELECT COALESCE(SUM(c.Logged,0))
SELECT SUM(ISNULL(c.Logged,0))
Is there a way to get this formatted correctly?
Cheers,
Lee
Put it outside:
SELECT COALESCE(
(
SELECT SUM(i.Logged)
FROM tbl_Sites s
INNER JOIN tbl_Incidents i
ON s.Location = i.Location
WHERE s.Sites = #SiteName AND i.[month] = DATEADD(mm, DATEDIFF(mm, 0, GetDate()) -1,0)
GROUP BY s.Sites
), 0) AS LoggedIncidents
If you are returning multiple rows, change INNER JOIN to LEFT JOIN
SELECT COALESCE(SUM(i.Logged),0)
FROM tbl_Sites s
LEFT JOIN tbl_Incidents i
ON s.Location = i.Location
WHERE s.Sites = #SiteName AND i.[month] = DATEADD(mm, DATEDIFF(mm, 0, GetDate()) -1,0)
GROUP BY s.Sites
By the way, don't put any function or expression inside aggregate functions if it's not warranted, e.g. don't put ISNULL, COALESCE inside of SUM, using function/expression inside aggregation cripples performance, the query will be executed with table scan
You'll have to use ISNULL like this -
ISNULL(SUM(c.Logged), 0)
Or, as Michael said, you can use a Left Outer Join.
I encountered this problem in Oracle.
Oracle does not have an ISNULL() function. However, we can use the NVL() function to achieve the same result:
NVL(SUM(c.Logged), 0)
The easiest, and most readable, way I've found to accomplish this is through:
CREATE PROC [dbo].[Incidents]
(#SiteName varchar(200))
AS
SELECT SUM(COALESCE(i.Logged, 0)) AS LoggedIncidents
FROM tbl_Sites s
INNER JOIN tbl_Incidents i
ON s.Location = i.Location
WHERE s.Sites = #SiteName
AND i.[month] = DATEADD(mm, DATEDIFF(mm, 0, GetDate()) -1,0)
GROUP BY s.Sites
You could wrap the SELECT in another SELECT like so:
CREATE PROC [dbo].[Incidents]
(#SiteName varchar(200))
AS
SELECT COALESCE(TotalIncidents ,0)
FROM (
SELECT
(
SELECT SUM(i.Logged) as TotalIncidents
FROM tbl_Sites s
INNER JOIN tbl_Incidents i
ON s.Location = i.Location
WHERE s.Sites = #SiteName AND i.[month] = DATEADD(mm, DATEDIFF(mm, 0, GetDate()) -1,0)
GROUP BY s.Sites
) AS LoggedIncidents
)
Just ran into this problem, Kirtan's solution worked for me well, but the syntax was a little off. I did like this:
ISNULL(SUM(c.Logged), 0)
Post helped me solve my problem though so thanks to all.
The code you've posted above
SELECT SUM(ISNULL(c.Logged,0))
would not work due to wrong order
what would work is the following
SELECT ISNULL(SUM(c.Logged),0)
It evaulates the expression SUM then if it returns NULL it is replaced with 0.