How to update a column for a set of rows? - sql

The below query gives a set of rows with 3 columns.
Select
c.CaseID, i.ImageID, i.ImagePath
From
tblCase c WITH (NOLOCK)
inner join
tblName n WITH (NOLOCK) on c.CaseID = n.CaseID
inner join
tblImage i WITH (NOLOCK) on n.NameID = i.NameID
where
n.NameCode = '70'
The ImagePath column will have data like this with semi colon separated values.
ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=Original;PageNumber=1
The ImageType value needs to be changed to "duplicate" as below for all the rows returned from the query.
ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=duplicate;PageNumber=1
Any ideas? Is using a cursor good to do this kind of update? The number of rows will be a couple of thousands.
Thank you!

The best idea would be to stop storing multiple values in one column and normalize the database so that you don't run into issues like this.
Barring that, you can try to use REPLACE(), but you need to be very careful that you don't inadvertently change parts of the string that happen to match with your string.
REPLACE(ImagePath, ';ImageType=Original;', ';ImagetType=Duplicate;')
might work, but if that attribute can appear at the end of the string (without a trailing semicolon) then it might fail. It could also fail if there is a space in between the "=" and the attribute/value in some cases. It could also fail if it might be the first attribute without a leading semicolon. There might be some other possible failure cases as well - which is why this isn't how you should be storing your data.

Here is a try:
declare #s varchar(max) = 'ImageID=3215;FilePath=\2016\5\13\test.tif;ImageType=original;PageNumber=1'
select substring(#s, 0, charindex('imagetype=', #s)) + 'ImageType=duplicate' +
substring(#s, charindex(';', #s, charindex('imagetype=',#s)), len(#s))
http://rextester.com/edit/AVQO58898
Description: take everything till imagetype= and add ImageType=duplicate to it and add everything from first semicolon that occurs afterimagetype= till the end.

Use REPLACE
UPDATE i
SET i.ImagePath = REPLACE(i.ImagePath, ';ImageType=Original;', ';ImageType=duplicate;')
From tblCase c WITH (NOLOCK)
inner join tblName n WITH (NOLOCK) on c.CaseID = n.CaseID
inner join tblImage i WITH (NOLOCK) on n.NameID = i.NameID
where n.NameCode = '70'

Related

Ignore leading zeros in JOIN condition?

I want to compare the field bseg~zuonr with aufk~aufnr in an inner join SQL select.
SELECT bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr FROM bseg INNER JOIN aufk
ON bseg~zuonr = aufk~aufnr "<--
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
This select is not working right for me and not giving back any data.
I think my problem is, that aufk~aufnr has leading zeros (for example: 000072667023) and bseg~zuonr contains only the number without leading zeros (for example: 72667023).
I have tried to use the TRIM-function inside the SQL select but that did not worked for me (Code snipped: ON bseg~zuonr = TRIM( LEADING '0' FROM aufk~aufnr ) → "(" is not allowed here. "." is expected.)
Did I do something wrong? Do you know any solution for this issue?
You could use the concat function. For example
SELECT bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr
FROM bseg
JOIN aufk ON concat( '0000', bseg~zuonr ) = aufk~aufnr
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
Also you can combine this with substring to set the aufnr exact to 12 chars
SELECT FROM bseg JOIN aufk ON ( ltrim( aufk~aufnr, '0' ) = bseg~zuonr )
FIELDS bseg~hkont, bseg~zuonr, bseg~belnr, bseg~gjahr, aufk~prctr
WHERE bseg~hkont IN #s_hkont
INTO TABLE #DATA(output).
is also working

How to perform Case statement inside a select statement?

I wanted to put 'No record' on the column instead of NULL if the datediff function returns a null value.
SELECT concat(e.firstname ,e.lastname) as Fullname,c.shiftcode as Shift, cast(c.datecheckinout as date) Date,datename(month, c.datecheckinout) as RecordMonth,c.timein , c.timeout,
CAST(
CASE
WHEN (datediff(HOUR,c.timein,c.timeout) IS NULL)
THEN 'No record'
END
), FROM tblCheckInOutDetail c RIGHT JOIN tblEmployee e on e.IdEmployee = c.IdEmployee WHERE e.IdEmployee = 55
So far this code only throws Incorrect syntax near 'CAST', expected 'AS'. but I don't know what data type should I put in the CAST parameter , since if there's a record it will show the datetime .
You need to convert the number value to a string. For this, you can use coalesce():
SELECT concat(e.firstname ,e.lastname) as Fullname,c.shiftcode as Shift, cast(c.datecheckinout as date) Date,datename(month, c.datecheckinout) as RecordMonth,c.timein , c.timeout,
COALESCE(CAST(datediff(HOUR, c.timein, c.timeout) AS VARCHAR(255)), 'No record')
FROM tblEmployee e LEFT JOIN
tblCheckInOutDetail c
ON e.IdEmployee = c.IdEmployee
WHERE e.IdEmployee = 55;
Note: I switched the RIGHT JOIN to a LEFT JOIN. They are equivalent logically. But most people find it much easier to follow the logic of the LEFT JOIN, because the table that defines the rows is the first table being read in the FROM clause.
Strictly answering question (though I don't understand why you need a CASE expression if you have working versions of the query), you can easily translate this to a CASE expression:
ISNULL(CAST(datediff(HOUR,c.timein,c.timeout) as varchar),'No Record')
ISNULL really is just nice, convenient shorthand for CASE WHEN a IS NOT NULL THEN a ELSE b END, so:
CASE WHEN DATEDIFF(HOUR, c.timein, c.timeout) IS NOT NULL
THEN CAST(datediff(HOUR,c.timein,c.timeout) as varchar(11))
ELSE 'No Record' END
As you can see, a downside is that if you really really really want a CASE expression, you have to repeat at least the DATEDIFF to cover both the case where the outer row doesn't exist and the case where the outer row exists but one of the values is NULL.
Also note that you should always specify a length for variable types like varchar, even in cases where you think you're safe with the default.
I don't know if this is the correct option or usage.
but this works for me :
ISNULL(CAST(datediff(HOUR,c.timein,c.timeout) as varchar),'No Record')
But can you guys show me how to do this using case expression?

SQL query throws error while using Alias in nested select

I posted one question today but that was too broad. So, I worked on that and now narrow down to some of parts. However, my query is returning syntax error while just copy paste the same text.
(
SELECT
TOP (100) PERCENT v_UpdateComplianceStatus.ResourceID, v_UpdateComplianceStatus.Status, CAST(DATEPART(yyyy, v_UpdateInfo.DatePosted) AS varchar(255)) + '-' + RIGHT('0' + CAST(DATEPART(mm, v_UpdateInfo.DatePosted) AS VARCHAR(255)), 2) AS MonthPosted, COUNT(1) AS Count
FROM
v_UpdateComplianceStatus
INNER JOIN
v_UpdateInfo
ON v_UpdateComplianceStatus.CI_ID = v_UpdateInfo.CI_ID
INNER JOIN
v_R_System
ON v_UpdateComplianceStatus.ResourceID = v_R_System.ResourceID
inner join
v_FullCollectionMembership fcm
on v_UpdateComplianceStatus.ResourceID = fcm.ResourceID
WHERE
(
v_R_System.Operating_System_Name_and0 like '%Workstation 6.1%'
and v_R_System.Obsolete0 = 0
)
AND
(
v_UpdateInfo.Severity IN
(
8,
10
)
)
AND
(
v_UpdateInfo.IsSuperseded = 0
)
AND
(
v_UpdateInfo.IsEnabled = 1
)
and fcm.CollectionID = 'ABC00328'
GROUP BY
v_UpdateComplianceStatus.ResourceID, v_UpdateComplianceStatus.Status, CAST(DATEPART(yyyy, v_UpdateInfo.DatePosted) AS varchar(255)) + '-' + RIGHT('0' + CAST(DATEPART(mm, v_UpdateInfo.DatePosted) AS VARCHAR(255)), 2)) FF
where Status =2
Group By MonthPosted ) E
where E.MonthPosted = E.MonthPosted
order by MonthPosted Desc
If I run the above query it is throwing error at
Group By MonthPosted ) EE
Not sure why it is giving error.
Msg 102, Level 15, State 1, Line 123
Incorrect syntax near 'EE'.
Some Important things which I discover.
This query works fine if I run some part of it.
(SELECT TOP (100) PERCENT v_UpdateComplianceStatus.ResourceID, v_UpdateComplianceStatus.Status, CAST(DATEPART(yyyy,
v_UpdateInfo.DatePosted) AS varchar(255)) + '-' + RIGHT('0' + CAST(DATEPART(mm, v_UpdateInfo.DatePosted) AS VARCHAR(255)), 2)
AS MonthPosted, COUNT(1) AS Count
FROM v_UpdateComplianceStatus INNER JOIN
v_UpdateInfo ON v_UpdateComplianceStatus.CI_ID = v_UpdateInfo.CI_ID INNER JOIN
v_R_System ON v_UpdateComplianceStatus.ResourceID = v_R_System.ResourceID
inner join v_FullCollectionMembership fcm on v_UpdateComplianceStatus.ResourceID=fcm.ResourceID
WHERE (v_R_System.Operating_System_Name_and0 like '%Workstation 6.1%' and v_R_System.Obsolete0 = 0) AND (v_UpdateInfo.Severity IN (8, 10)) AND (v_UpdateInfo.IsSuperseded = 0) AND (v_UpdateInfo.IsEnabled = 1)
and fcm.CollectionID='ABC00328'
GROUP BY v_UpdateComplianceStatus.ResourceID, v_UpdateComplianceStatus.Status, CAST(DATEPART(yyyy,
v_UpdateInfo.DatePosted) AS varchar(255)) + '-' + RIGHT('0' + CAST(DATEPART(mm, v_UpdateInfo.DatePosted) AS VARCHAR(255)), 2))
But if I Put Alias (FF) then it is throwing a syntax error.
Too long for a comment. Here is your first snippet condensed into something readable. Note - learn to write and post readable code. You have gone with FAR too much line spacing, indentation, and white space for anyone to easily read your code. The harder it is to read, the harder it is to understand. I've done my best to condense your first query into the essential elements.
(
SELECT blah blah,
CAST(DATEPART(yyyy, v_UpdateInfo.DatePosted) AS varchar(255)) + '-' +
RIGHT('0' + CAST(DATEPART(mm, v_UpdateInfo.DatePosted) AS VARCHAR(255)), 2) AS MonthPosted,
<aggregated column>
GROUP BY blah blah) as FF
where Status =2
Group By MonthPosted
) as E
where E.MonthPosted = E.MonthPosted
order by MonthPosted Desc
So what do YOU see wrong here. The where clause is pointless - does nothing useful. You probably introduced that error with all the editing. And apparently you cast numbers to large strings for no reason. That is just sloppy. It is concerning that you feel a need to cast a number to zero-filled string in the first place - that is probably an inefficient approach. If you really need to do that, look up the documentation for convert. Style 112 does what you need - all you need to do is take the first 6 characters of the converted string. Note 6 characters, not 255 characters or MAX characters. That will declutter your code significantly.
And now that you have edited your post multiple times, it logically makes no sense. There is no "EE" alias in your first query at all - so the error you posted cannot come from that snippet. Most likely the problem comes from the code you left out.
So now it is time to divide and conquer - a technique you can use to build complicated queries. Focus on that snippet ONLY. Write it as a complete query and run it, test it, validate that it works. When it does execute without errors and returns the correct results (results that you have actually verified and not just glanced at to see if numbers/values look "reasonable"), you can then add additional logic as needed. Usually it is best to add joins 1 by 1 to avoid creating a monster problem that is difficult to understand and diagnose. Often the use of CTEs can help. Put your starting query in a cte, get it working correctly. Example:
with cte1 as (...)
select * from cte1
order by ...;
Then add another cte to this first one and write it to use the first one, get it working. Example:
with cte1 as (...),
cte2 as (select ... from cte1 inner join ...)
select * from cte2
order by ...;
Repeat that as needed. Once everything works you can try to bring it all together and "beautify" it if needed.
And start thinking about your code. Use the appropriate datatypes, do NOT try to prematurely optimize things, learn and understand your schema, and stop using tricks. As I mentioned, "select top 100 percent" is generally pointless. Rhetorical question - why do you think this is needed as a part of this derived table. And use meaningful alias names. "E" and "EE" are not meaningful. Remember that someone will need to maintain this code, perhaps even modify it. And, of course, create an alias for every table/view and use it. Something short (but not too short) but meaningful. This will vastly improve readability - especially with those very long view (presumably) names.
Lastly, You said "This query works fine if i run some part of it." That just is not a useful thing to write since it means nothing to the reader. Which part? All of it? The first line? Just lines 2 through 5? It is difficult to have a technical discussion - do not add confusion by using terms that are imprecise.

Format sql column when using select

I have the following query to select record but i wan to format the column on the result set.
SELECT
COALESCE(dbo.tblMitchellLandscapeID.PatchSize,0) as PatchSize,
dbo.tblMitchellLandscape.MitchellLandscapeName
FROM tblMitchellLandscapeID
INNER JOIN dbo.tblMitchellLandscape
ON dbo.tblMitchellLandscapeID.MitchellLandscapeID=dbo.tblMitchellLandscape.MitchellLandscapeID
WHERE AssessmentVersionID = #AssessmentVersionID
"PatchSize" is a decimal value so it stored always like two decimals "15.10". All i trying to format to one decimal when the select statement is executed i wan to populate the result set like "15.1" rather than 15.10.
You can just cast it to the format you want:
SELECT CAST(COALESCE(li.PatchSize, 0) as decimal(5, 1)) as PatchSize,
l.MitchellLandscapeName
FROM tblMitchellLandscapeID li INNER JOIN
dbo.tblMitchellLandscape l
ON li.MitchellLandscapeID = l.MitchellLandscapeID
WHERE AssessmentVersionID = #AssessmentVersionID;
Notice the query is also easier to read (and write) if you use table aliases.

SQL Doesnt Want to match strings with spaces for some reason

I have this SQL Query that is not comparing properly so I commented it out the WHERE clause. When returning the AF.ActivityNote it always has 2 spaces after it no matter if I do RTRIM on it or not. I think those spaces are the issue that wont let the commented WHERE clause to properly match the string against userfield33.
SELECT CAST(UF.UserField33 AS NVARCHAR) , RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
FROM [BCMTEST01].[dbo].[ActivityContacts] as AC INNER JOIN [BCMTEST01].[dbo].[ActivityFullView] as AF
ON AC.ActivityID = AF.ActivityID INNER JOIN [BCMTEST01].[dbo].[OpportunityExportView] as OP
ON AC.ContactID = OP.ContactServiceID INNER JOIN [BCMTEST01].[dbo].[UserFields] as UF
ON OP.ContactServiceID = UF.ContactServiceID
WHERE ContactID = 8376
--WHERE RTRIM(CAST(UF.UserField33 AS NVARCHAR) = RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
ORDER BY ContactID ASC
First, you should always include the length when converting to nvarchar, varchar, char, and nchar. So use something like:
cast(uf.userfield33 as nvarchar(255)) -- or whatever length you like, so long as you have something
The last two characters are not spaces. Do something like:
select ascii(right( AF.ActivityNote, 1))
To see what the character value is. You can then use replace to get rid of it. Or, you can just chop off the last two characters (if that works for your application).
By the way, I am assuming you are using SQL Server based on the syntax of the query.
Here is an alternative where clause:
where (case when right(AF.ActivityNote, 2) = char(10)+CHar(13)
then LEFT(AF.ActivityNote, LEN(AF.ActivityNote) - 2)
else AF.ActivityNote
end) = CAST(UF.UserField33 AS NVARCHAR(255)
I'm not a big fan of case statements in where clauses. I would actually put the logic in a subquery. Also, I might have the order of the 10/13 backwards.