Update table with date conversion failing on Multi-Part Identifier - sql

Thanks to the guys with suggestions on date conversion yesterday, I now have a working SELECT script.
Unfortunately, when I try to turn it into an UPDATE script, I get the dreaded
Msg 4104, Level 16, State 1, Line 25
The multi-part identifier "mbrProject.ID" could not be bound.
The entire script should insert the date from mbrProject into ProjectDates, for each matching ID (mbrProject.[ID] = ProjectDates.[Project_ID]), whilst resolving mixed US & UK format dates in mbrProject, due to users having incorrect country settings when updating the tables (not changeable from my end).
Update ProjectDates
SET ProjectDates.[Start_Date] =
(
select right([Start_Date],4) +
case
when len([Start_Date])=10 then
substring([Start_Date],4,2) + left([Start_Date],2)
else right('0' + left([Start_Date],firstIndex-1),2) +
right('0' + substring([Start_Date],firstIndex+1,secondIndex - firstIndex-1),2)
end
from
(
select mp.[Start_Date], charindex('/',mp.[Start_Date],1) firstIndex,
charindex('/',mp.[Start_Date],charindex('/',mp.[Start_Date],1)+1) secondIndex
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
where mbrProject.[ID] = ProjectDates.Project_ID
)
If I run ONLY the SELECT statement, it works fine, returning the correct values.
i.e Everything from
select right([Start_Date],4) +
case
down to
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
However, as soon as I try to wrap it up in the UPDATE statement, I get the error.
I know that this is down to syntax, but wherever I try to move stuff, I can't quite figure it out.
Any ideas please?
Thanks
Craig

Try this:
UPDATE PR
SET PR.[Start_Date] = A.[Corrected_Start_Date]
FROM ProjectDates PR
JOIN
(
SELECT
[Id],
RIGHT([Start_Date],4) +
CASE
WHEN len([Start_Date])=10
THEN substring([Start_Date],4,2) + LEFT([Start_Date],2)
ELSE RIGHT('0' + LEFT([Start_Date],firstIndex-1),2) +
RIGHT('0' + substring([Start_Date],firstIndex+1,secondIndex - firstIndex-1),2)
END [Corrected_Start_Date]
FROM
(
SELECT
[Id],
[Start_Date],
charindex('/',[Start_Date],1) firstIndex,
charindex('/',[Start_Date],charindex('/',[Start_Date],1)+1) secondIndex
FROM mbrProject
) S
) A
ON A.[ID] = PR.[Project_ID]

(
select mp.[Start_Date], charindex('/',mp.[Start_Date],1) firstIndex,
charindex('/',mp.[Start_Date],charindex('/',mp.[Start_Date],1)+1) secondIndex
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
At the end of the last line here, the names mp, pd, mbrProject and (the inner ProjectDates) no longer exist as table names or aliases. The only name applicable to this row set from here on is A, the alias you've provided.
So you need to include mp.ID in your select list, and then use A.ID in your outer comparison.
Also, not knowing what you're trying to do, I'd just want to make sure you're aware that ProductDates (the table being updated) and pd are referring to two separate instances of that table, an inner one and an outer one. I'm hoping that the final WHERE should be:
where A.[ID] = ProjectDates.Project_ID

The problem is that doing
Update ProjectDates
SET ProjectDates.[Start_Date] = (select ...)
you are trying to set one field of one row to the results of the sub-select statement, which, I presume, is returning multiple values.

Related

Single Query To Select Based On Parameters If Or not supplied

I have used SqlDataSource and have a select query based on District & Zone as below
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director') AND ((convert(varchar,a.districtid) LIKE '%2%') AND (convert(varchar,a.zoneid) LIKE '%25%')) ORDER BY a.[committee_id] DESC
It's an inline query. I have tried above query but not able to figure out how to Select condition based.
I want if district supplied then Select according to District, if both District & Zone supplied then Select according to both & If nothing supplied then Select All. But should be in single query. How should I do this?
First, fix your query so you are not using meaningless table aliases. Use table abbreviations! I would also drop all the square braces; they just make the query harder to write and to read.
Basically, you want comparisons with NULL in the WHERE clause. I have no idea why your sample code uses LIKE, particularly columns that appear to be numbers. Nothing in the question explains why LIKE is used for the comparison, so the idea is:
SELECT cd.committee_id as memberid, cd.membername,
cd.memberemail, cd.memberdesignation, cd.membercreatedby,
dm.districtname AS district, dm.districtid,
zm.zone_name AS zone, zm.zoneid
FROM committee_details cd LEFT JOIN
district_master dm
ON cd.districtid = dm.districtid LEFT JOIN
zone_master zm
ON zm.districtid = cd.districtid AND
zm.zoneid = cd.zoneid
WHERE cd.membercreatedby = 'director') AND
(cd.districtid = #district or #district is null) AND
(cd.zoneid = #zone or #zone is null)
ORDER BY cd.[committee_id] DESC;
If you were using LIKE, then I would phrase the logic like:
WHERE cd.membercreatedby = 'director') AND
(cast(cd.districtid as varchar(255)) like #district) AND
(cast(cd.zoneid as varchar(255)) like #zone)
And pass in the patterns as '%' when you want all values to match. This assumes that the columns in cd are not NULL. If they can be NULL, then you want an explicit comparison, as in the first example.
If I got the question right then you can use parameters and compare to the column itself if the values are not supplied or not present.
try the following:
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director')
AND b.districtname = isnull(nullif(#districtname, ''), b.districtname)
AND c.zone_name = isnull(nullif(#zone_name, ''), c.zone_name)
ORDER BY a.[committee_id] DESC

Adding WHERE clause to outer query causes inner query to error

The below query worked until I added a WHERE clause.
SELECT
PersonTable.FullName,
View_PersonToHead.DirectorId
FROM PersonTable
LEFT JOIN View_PersonToDirector ON PersonTable.PersonId = View_PersonToDirector.PersonId
WHERE View_PersonToDirector.DirectorId = 12345 --No error if this line is removed
The error message is:
Invalid length parameter passed to the RIGHT function.
This leads me to believe that there was an error with how I wrote the View_PersonToDirector view. Something about adding the WHERE clause causes the query to be evaluated/optimized in a different way, exposing some issue.
Internals of View_PersonToDirector:
WITH items AS (
SELECT
PersonId,
0 AS [Level],
CAST(PersonId AS VARCHAR(255)) AS [Path]
FROM PersonTable
UNION ALL
SELECT
e.PersonId,
[Level] + 1,
CAST([Path] + ' < ' + CAST(e.PersonId AS VARCHAR(255)) AS VARCHAR(255))
FROM PersonTable e
INNER JOIN items itms ON itms.PersonId = e.ManagerId
)
SELECT
A.PersonId,
CASE
WHEN A.[Level] = 1
THEN A.PersonId
ELSE CAST(LEFT(A.PathToDirector, CHARINDEX(' ', A.PathToDirector)) AS INT)
END AS DirectorId
FROM (
SELECT
items.PersonId,
items.[Level],
RIGHT(items.[Path], LEN(items.[Path])-7) AS PathToDirector
FROM items
WHERE Path LIKE '1111 < %' --Id of director
) A
I suspect that having a WITH cte in the view causes the query optimizer to work differently, applying the WHERE filtering in a different order. Is this bad practice?
One of your problems is definitely in this code:
RIGHT(items.[Path], LEN(items.[Path])-7) AS PathToDirector
I appreciate that you think that this WHERE clause fixes the problem:
WHERE Path LIKE '1111 < %'
But it does not. The problem is that SQL Server does not guarantee the order of evaluation of expressions. This true even for subqueries, CTEs, and views. These can be evaluated in any order. In fact, SQL Server sometimes pushes the evaluation to the node that reads from the table -- which is why you get an error.
Personally, I think this is a bug in SQL Server. Those powers that be do not agree. Here are two solutions:
(CASE WHEN Path LIKE '1111 < %' THEN RIGHT(items.[Path], LEN(items.[Path])-7) END) AS PathToDirector
Or:
(CASE WHEN Path LIKE '1111 < %' THEN RIGHT(items.[Path], LEN(items.[Path] + '1234567')-7) END AS PathToDirector
You may have the same problem with the CHARINDEX().
The use of a where condition related to column from left join table generate and implicit inner join
In this case add the condition to the ON clause for let the left join work
SELECT
PersonTable.FullName,
View_PersonToHead.DirectorId
FROM PersonTable
LEFT JOIN View_PersonToDirector ON PersonTable.PersonId = View_PersonToDirector.PersonId
AND View_PersonToDirector.DirectorId = 12345
for the length problem try use conditional eg using case
SELECT
items.PersonId,
items.[Level],
case when LEN(items.[Path]) > 7 then RIGHT(items.[Path], LEN(items.[Path])-7)
ELSE items.[Path] END AS PathToDirector
FROM items
The base part of your rCTE has:
CAST(PersonId AS VARCHAR(255)) AS [Path]
Which means base rows of the rCTE would contain values such as 1234 which are shorter than 7 characters and cause RIGHT(x, LEN(x) - 7) to fail. The condition:
RIGHT(items.[Path], LEN(items.[Path])-7) AS PathToDirector
Could be safely written as:
SUBSTRING(items.[Path], NULLIF(CHARINDEX(' < ', items.[Path]), 0) + 3, LEN(items.[Path]))

Invalid Column in SQL SubQuery

I am trying to run a query below and I am getting the following errors and unable to figure out.
Please look at how column AllocPer is being calculated. That's where the errors are coming from:
Msg 207, Level 16, State 1, Procedure USP_RS_Dealio_JLL_ECRDetails_test, Line 688
Invalid column name 'dealid'.
Msg 207, Level 16, State 1, Procedure USP_RS_Dealio_JLL_ECRDetails_test, Line 689
Invalid column name 'empid'.
My SQL code:
SELECT
MarketPerDiff, CommissionDate, empid, dealid
INTO
#vwDealEmpSplitDetail_Emp
FROM
dbo.vwDealEmpSplitDetail_Emp
PRINT 'Query 1 Starts at ' + CONVERT(nvarchaR(36), getdate(), 114)
SET# t1 = GETDATE()
SELECT
Per.enddate "CommEndDate",
'Period ' + CAST(Per.Period AS VARCHAR) "SubPeriod",
Col.EligibleDate AS "CollectionDate",
Col.DealID,
Client.clientName,
Deal.DealName,
Col.EmpID AS "ProfID",
Emp.FullName AS "ProfName",
SUM(ISNULL(Col.CashCollected, 0)) CashCollected,
Stat.MarketID,
Stat.OpUnit,
HB.Description,
SUM(ISNULL(Col.CostHurdle, 0)) AS "DEmpCostHurdle",
ISNULL(Prof.DealCostMultiplier, 50)[DealCostMultiplier],
(SELECT SUM(MarketPerDiff) "MarketPerDiff"
FROM #vwDealEmpSplitDetail_Emp
WHERE #vwDealEmpSplitDetail_Emp.dealid = Deal.DealID AND
#vwDealEmpSplitDetail_Emp.empid = Emp.EmpID) as AllocPer
INTO
#SummedValues
FROM
tblEmpCollectionAdj Col WITH(NOLOCK)
JOIN
tblDeal Deal WITH(NOLOCK) ON Deal.DealID = Col.DealID
LEFT JOIN
dbo.tblClient Client WITH(NOLOCK) ON Client.ClientCode = Deal.ClientCode
JOIN
tblMktOpUnitCompStatus Stat WITH(NOLOCK) ON Stat.BatchID = Col.BatchID
LEFT JOIN
dbo.tblEmployee Emp WITH(NOLOCK) ON Emp.EmpID = Col.EmpID AND Emp.Active = 1
LEFT JOIN
dbo.tblCommPeriod Per WITH(NOLOCK) ON Col.EligibleDate BETWEEN Per.StartDate AND Per.Enddate
LEFT JOIN
tblEmpCompProfile Prof WITH(NOLOCK) ON Prof.EmpID = Col.EmpId
AND Prof.Active = 1
AND Prof.PeriodID = #PeriodId
AND Prof.Batchid = Col.Batchid
LEFT JOIN
tblHBAlloc HB ON HB.HBAcctEmpID = Prof.EmpID
AND HB.OpUnit = Prof.OpUnit
AND HB.CF3 = Prof.MarketId
AND HB.FiscalYear = #Year1
WHERE
Col.Active = 1
AND Deal.Active = 1
AND Col.PeriodId = #PeriodId
AND ISNULL(Col.CashCollected, 0) + ISNULL(Col.CostHurdle, 0) NOT BETWEEN - .01 AND.01
GROUP BY
Per.enddate,
'Period ' + CAST(Per.Period AS VARCHAR),
Col.EligibleDate, Col.DealID, Client.clientName,
Deal.DealName,
Col.EmpID,
Emp.FullName,
Col.CashCollected,
Stat.MarketID, Stat.OpUnit,
HB.Description,
ISNULL(Prof.DealCostMultiplier, 50),
deal.dealid, Emp.empid, Per.StartDate, Per.Enddate
PRINT 'Query 1 Ends ' + CONVERT(nvarchaR(36), getdate(), 114)
SET# t2 = GETDATE()
PRINT ' TIME ELAPSED ' + CAST(DATEDIFF(millisecond, #t1, #t2) AS NVARCHAR(255))
The error should be self-explanitory. It seems that you are referencing a column that does not exist in a table you are trying to access it from. Without access to your table structure, unfortunately we can only guess at the issue. However, your error says that the columns dealid and empid are invalid. I see that they are being used in several places.
Check to ensure that dealid exists in the following tables/views: tblEmpCollectionAdj, vwDealEmpSplitDetail_Emp, tblDeal.
And check that empid exists in the following tables/views: vwDealEmpSplitDetail_Emp, tblEmpCollectionAdj, tblEmployee, tblEmpCompProfile.
Also, a point that #Blorgbeard mentioned in a comment, check that you are using the proper casing for the column and for table aliases. You have the table tblDeal aliased as Deal, however you reference it as deal in at least one place.

Complex Query Incorrect Syntax Error

I have tried to search for a solution to this but I have not been able to find one that fits this situation.
First I must say that my SQL is a lot rusty. The following query is the most complex one I have ever done to date.
Here is the query:
Declare #root varchar(Max)
set #root = ''
Select
ib.irrnum, ib.status, pu.probtype,
ib.submitby, ta.[Task Action], ib.area, co.cost,
rc.rootcause, ib.jobnum
From
tbl_irrbase ib
Left Join
tbl_cost co On ib.irrnum = co.irrnum
Left join
(Select Distinct probtype, irrnum
From tbl_probtype) pu On ib.irrnum = pu.irrnum
Left Join
(Select Distinct rootcause, irrnum
From tbl_rtcause) rc On ib.irrnum = rc.irrnum
Left Join
(Select TOP 1
(owner + Space(1) + Convert(varchar(10), senddate, 101) + Space(1) + taskitem) As 'Task Action',
irrnum
From
(select * From tbl_taskaction) ta
Order by
senddate Desc, sendtime Desc) ta On ib.irrnum = ta.irrnum
left Join
(Select [#root] = #root + rs.rootsource + Space(3), irrnum
From tbl_rtsource rs
Where rs.entrydate Between '10/04/2016' And '10/06/2016'
Select #root As 'Root Source') sr On ib.irrnum = sr.irrnum
Where
ib.submitedate between '09/28/2016' And '10/05/2016'
My problem is with the last Left Join line. If I take the entire Select statement out and run it in SSMS it runs fine, no errors. But when I try and run it in this query I get an error, red squiggly line under 'Select #root As' telling me the following:
Incorrect Syntax near 'Select'.
Expecting ')', EXCEPT, or UNION
I do not know how to fix this. If I remove this last 'Left Join' line the query runs fine.
Any ideas?
Instead of the last LEFT JOIN, try something like this:
CROSS APPLY (
SELECT (
SELECT rs.rootsource + Space(3)
From tbl_rtsource rs
Where rs.entrydate Between '10/04/2016' And '10/06/2016'
AND rs.irrnum=ib.irrnum
FOR XML PATH('')
) AS rootsource
) sr
Then include sr.rootsource in the columns of the first SELECT.

Trying to combine Inner Join and two where statements with a Select Max by date and save result into variable

I'm trying to use a inner join to combine 3 tables into one and pull 2 variables based on the most recent date of entry in a medical database.
I'm looking to pull the last location a patient was seen at and the doctor at that visit, which I will pass into another command later in my query. I will save those as #last_location and #doctor_name respectively. I am using #last_date to try to make a select max to get the last visit only for each given patient. However, blank values are passing forward on my variables (both #doctor_name and #last_location). Can anyone help clean this up? Appreciate the help!
My code is:
SELECT #last_location = location_mstr.location_name, #last_date = Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 5, 2) + '/' + Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 7, 2) + '/' + Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 3, 2), #doctor_name = provider_mstr.description
FROM
location_mstr
INNER JOIN patient_encounter ON location_mstr.location_id = patient_encounter.location_id
INNER JOIN provider_mstr ON patient_encounter.rendering_provider_id = provider_mstr.provider_id
Where (patient_encounter.person_id = #person_id) and (#last_date = MAX(#last_date))
I also tried changing the last statement based on some threads here to:
Where #last_date = (SELECT MAX(#last_date) FROM patient_encounter WHERE patient_encounter.person_id = #person_id)
In the where clause of your original query, it looks like you are trying to find the patient_encounter record with the most recent billable_timestamp. The way you are referencing the #last_date variable in the where clause isn't going to do anything.
Instead, you can just get the TOP 1 most recent row and ORDER BY billable_timestamp DESC to get what you're looking for.
I also changed the string expression in your select list that sets #last_date to use the SQL CONVERT function. You can see a list of date formats that CONVERT can do here: http://msdn.microsoft.com/en-us/library/ms187928.aspx
SELECT TOP 1
#last_location = location_mstr.location_name
,#last_date = CONVERT(VARCHAR, patient_encounter.billable_timestamp, 1)
,#doctor_name = provider_mstr.description
FROM location_mstr
INNER JOIN patient_encounter
ON location_mstr.location_id = patient_encounter.location_id
INNER JOIN provider_mstr
ON patient_encounter.rendering_provider_id = provider_mstr.provider_id
WHERE patient_encounter.person_id = #person_id
ORDER BY patient_encounter.billable_timestamp DESC