querying information from next row - sql

I created this SQL and dont know how to query the next row. We use SQL 2008 so cant use lag/lead
SELECT P_MTN AS MTN
,P_DATE AS DATE
,CONVERT(VARCHAR(50), SEQU) AS NUM
,item_id + ' || ' + CONVERT(VARCHAR(50), PRODUCTION_ID) + ' || ' +
display_description AS ITEM_1
FROM dbo.Equipment INNER JOIN
dbo.ERAT ON SEQUENCE = SEQU INNER JOIN
Track.dbo.item_link ON link_id = PRODUCTION_ID INNER JOIN
Track.dbo.LinkParentDescription ON item_id = item_id
ORDER BY NUM ASC
Basically what I want to do is..
If the NUM value is the same as the next row's NUM value then add a new column populated with
item_id + ' || ' + CONVERT(VARCHAR(50), PRODUCTION_ID) + ' || ' + display_description AS ITEM_2
using the info from the next row.
I've had to anonnymise this code as I was told to do so, so hopefully the code is still valid (lol)

Can you use a window function on SQL Server 2008? The equivalent of LEAD:
MAX(NUM) OVER(ORDER BY NUM ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)
This expression will give you the NUM value of the next row, where the rows are ordered by NUM ascending. Then just do a comparison with a CASE expression:
CASE
WHEN NUM = MAX(NUM) OVER(ORDER BY NUM ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING)
THEN item_id + ' || ' + CONVERT(VARCHAR(50), PRODUCTION_ID) + ' || '
+ display_description
ELSE YYY
END AS ITEM_2

Related

Query Filter based on condition

I have this query (SQL Server 2019) and I actually wanted to add a filter to it to show only items where IssueStatusID = 1 (This column is based on int Data Type)
Can anyone help with this or point me in the right direction?
SELECT ID,
STRING_AGG(TRY_CONVERT(varchar, Issue#, 101) + ': ' + Notes + CHAR(13) + CHAR(10) + CHAR(13), CHAR(10)) WITHIN GROUP (ORDER BY Issue# DESC) AS IssueNotes
FROM (SELECT DISTINCT
ac4.ID,
nd.Notes,
nd.Issue#,
nd.IssueStatusID
FROM dbo.IssueTracking AS nd
INNER JOIN dbo.StatusUpdates AS ac4 ON ac4.ID = nd.ReleaseTrackerID) AS vNotes
GROUP BY ID;
Add the WHERE clause as shown below. The WHERE clause limits the data being returned.
SELECT ID,
STRING_AGG(TRY_CONVERT(varchar, Issue#, 101) + ': ' + Notes + CHAR(13) + CHAR(10) + CHAR(13), CHAR(10)) WITHIN GROUP (ORDER BY Issue# DESC) AS IssueNotes
FROM (SELECT DISTINCT
ac4.ID,
nd.Notes,
nd.Issue#,
nd.IssueStatusID
FROM dbo.IssueTracking AS nd
INNER JOIN dbo.StatusUpdates AS ac4 ON ac4.ID = nd.ReleaseTrackerID
WHERE nd.IssueStatusID = 1
) AS vNotes
GROUP BY ID;

Manipulating duplicate values?

I have a table, with an ID, FirstName & Lastname.
I'm selecting that using the following query:
SELECT USER_ID as [ID], First_P + ' ' + Last_P as FullName FROM Persons
It's working fine. I'm basically having a list of ID's and full names.
Full names could be the same. How is it possible for me to find them and add the ID on the Full name cell as well? only when the names are the same.
Example:
1 John Wick (1)
50 John Wick (50)
I haven't found any similar questions to be honest, at least not for MSSQL. So If there are any, feel free to link me.
please take a look my answer. I used nested query to identify number of duplicated names
SELECT
ID,
IIF(NUMBEROFDUPS =1, NAME, CONCAT(NAME, ' (', ID, ')')) AS NAME
FROM
(
SELECT
ID,
CONCAT(First_P, ' ', Last_P) AS NAME,
COUNT(*) OVER (PARTITION BY First_P,Last_P) AS NUMBEROFDUPS
FROM
Table1
) tmp;
You can use outer apply to group the items via First_P + ' ' + Last_P
and then add case for multiple items.
The select stuff should look like:
SELECT USER_ID as [ID], p1.First_P + ' ' + p1.Last_P + case when cnt.FullName is not null
then '(' + p2.[sum] + ')' else '' end as FullName FROM Persons p1
outer apply (select First_P + ' ' + Last_P as FullName,count(1) as [sum]
from Persons p2
where p2.First_P + ' ' + p2.Last_P = p1.First_P + ' ' + p1.Last_P
group by First_P + ' ' + Last_P
having count(1) > 1) cnt

Updating database column with string built based on value of another column

I have a table with a column called Days. The Days column stores a comma delimited string representing days of the week. For example the value 1,2 would represent Sunday, Monday. Instead of storing this information as a comma delimited string, I want to convert it to JSON and store it in a column called Frequency in the same table. For example, a record with the Days value of 1,2 should be updated to store the following in it's Frequency column:
'{"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}'
I found a way to do this using a case statement assuming that there is only one digit in the Days column like so:
UPDATE SCH_ITM
SET
FREQUENCY =
CASE
WHEN SCH_ITM.DAYS = 1 THEN '{"weekly":{"interval":1,"Sunday":true,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 2 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 3 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":true,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 4 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":true,"Thursday":false,"Friday":false,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 5 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":true,"Friday":false,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 6 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":true,"Saturday":false}}'
WHEN SCH_ITM.DAYS = 7 THEN '{"weekly":{"interval":1,"Sunday":false,"Monday":false,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":true}}'
END
WHERE SCH_TYPE = 'W';
However I cannot seem to figure out an effecient way to handle converting a value such as 1,5 into the correct JSON representation. Obviously I could write out every possible permutation, but surely is a better way?
Okay this will give you what you have asked for
create table test (days varchar(20), frequency varchar(500))
insert into test(days) values('1'),('2'),('3'),('4'),('5'),('6'),('7'),('1,5')
update test set frequency = '{"weekly":{"interval":1,'
+ '"Sunday": ' + case when days like '%1%' then 'true' else 'false' end + ','
+ '"Monday": ' + case when days like '%2%' then 'true' else 'false' end + ','
+ '"Tuesday": ' + case when days like '%3%' then 'true' else 'false' end + ','
+ '"Wednesday": ' + case when days like '%4%' then 'true' else 'false' end + ','
+ '"Thursday": ' + case when days like '%5%' then 'true' else 'false' end + ','
+ '"Friday": ' + case when days like '%6%' then 'true' else 'false' end + ','
+ '"Saturday": ' + case when days like '%7%' then 'true' else 'false' end + '}}'
select * from test
Though of course e.g. Days = '1234' will produce the same as '1,2,3,4' - as will 'Bl4arg3le12' for that matter. If Days is a string, you can put '8' which is meaningless?
Really it sounds like you need an extra table or two:
If "MyTable" is the table with the Days column, add a Days table with the days of the week, then a MyTableDays table to link MyTable entries to days - for the 1,5 example, there would be two rows in MyTableDays
With the help of a parse function and an cross apply
;with cteDays As (Select ID,Name From (Values(1,'Sunday'),(2,'Monday'),(3,'Tuesday'),(4,'Wednesday'),(5,'Thursday'),(6,'Friday'),(7,'Saturday')) D(ID,Name))
Update YourTable Set Frequency = '{"weekly":"interval":1,'+String+'}}'
From YourTable A
Cross Apply (
Select String = Stuff((Select ','+String
From (
Select String='"'+Name+'":'+case when RetVal is null then 'false' else 'true' end
From [dbo].[udf-Str-Parse](A.Days,',') A
Right Join cteDays B on RetVal=ID) N
For XML Path ('')),1,1,'')
) B
Select * from YourTable
Updated Table
Days Frequency
1,2 {"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":false,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}
1,2,3 {"weekly":"interval":1,"Sunday":true,"Monday":true,"Tuesday":true,"Wednesday":false,"Thursday":false,"Friday":false,"Saturday":false}}
The UDF if needed
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>'+ Replace(#String,#Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')

Ordering SQL SELECT by result of a string comparison

I have a table with two string columns, ID and LANGUAGE. Language can be one of CYM, ENG, GAE.
When selecting data from the table, I want to order it by the language column, putting a specified language at the start of the results, with the other languages later, in any order.
Say I have the data
+===+=====+
+ 1 + CYM +
+ 2 + GAE +
+ 3 + ENG +
+ 4 + CYM +
+===+=====+
and I want the output to be
+===+=====+
+ 3 + ENG +
+ 1 + CYM +
+ 2 + GAE +
+ 4 + CYM +
+===+=====+
How do I do the equivalent of
SELECT ID, LANGUAGE
FROM TABLE
ORDER BY (LANGUAGE = 'ENG'), ID
You can use CASE WHEN to ensure ENG will be first:
SELECT ID, LANGUAGE
FROM your_table
ORDER BY
CASE LANGUAGE WHEN 'ENG' THEN 0
ELSE 1
END ASC;
-- ,ID ASC -- if needed
LiveDemo

SQL query returns multiple rows when trying to find specific value

I have 2 tables. One is called "Tasks" and the other one is called "TaskDescription"
in my "Task" the setup looks like this:
"taskID(primary)","FileID","TaskTypeID" and a bunch of other columns irrelevant.
Then in my "TaskDescription", the setup looks like:
"TaskTypeID", "TaskTypeDesc"
so for example if TaskTypeID is 1 , then the description would be"admin"
or if TaskTypeID is 2, then TaskTypeDesc would be "Employee" etc.
The two tables have a relationship on the primary/foreign key "TaskTypeID".
What I am trying to do is get a task id, and the TaskDesc where the FileID matches the #fileID(which I pass in as a param). However in my query I get multiple rows returned instead of a single row when trying to obtain the description.
this is my query:
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast((SELECT DISTINCT td.tasktypedesc FROM casefiletaskdescriptions
td JOIN
casefiletasks cft ON td.tasktypeid=cft.tasktypeid WHERE cft.taskid =
1841 )AS
NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'
I am trying to get the output to look like "Task ID: 1234 - Admin - Investigator : John Doe". However I am having trouble on this part:
CAST((select DISTINCT td.TaskTypeDesc from CaseFileTaskDescriptions td
JOIN CaseFileTasks cft ON td.TaskTypeID=cft.TaskTypeID
where cft.TaskID =1841 )as nvarchar(100))
This seems to work but the problem is I have to hard code the value "1841" to make it work. Is there a way to assign a "taskID" variable with the values being returned from the TaskID select query, or will it not work since I think sql runs everything at once instead of line by line.
EDIT-this is in Microsoft SQL Server Management Studio 2008
You can dynamically reference a column that exists in your FROM set. In this case, it would be any column from casefiletasks or investigators. You would replace 1841 with the table.column reference.
Update
Replacing your static integer with the column reference, your query would look like:
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast((SELECT DISTINCT td.tasktypedesc FROM casefiletaskdescriptions
td JOIN
casefiletasks cft ON td.tasktypeid=cft.tasktypeid WHERE cft.taskid =
cf.taskid )AS
NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'
Would this work as your inner query?
SELECT DISTINCT td.TaskTypeDesc FROM CaseFileTaskDescriptions td
JOIN CaseFileTasks cft ON td.TaskTypeID = cft.TaskTypeID
WHERE cft.TaskID = cf.TaskID
Why not just do another join instead of a subquery?
SELECT taskid,
( 'Task ID: '
+ Cast(cf.taskid AS NVARCHAR(15)) + ' - '
+ Cast(td.tasktypedesc AS NVARCHAR(100))
+ ' - Investigator : ' + ( Cast(i.fname AS NVARCHAR(20)) + ' '
+ Cast(i.lname AS NVARCHAR(20)) ) ) AS
'Display'
FROM casefiletasks [cf]
JOIN investigators i
ON CF.taskasgnto = i.investigatorid
JOIN casefiletaskdescriptions td
ON td.tasktypeid = cf.tasktypeid
WHERE cf.fileid = 2011630988
AND cf.concluded = 0
AND cf.progressflag != 'Conclude'