SQL Server 2019. Need to update particular column in particular row - sql

I have table like this:
LinN | RecType | Value
-----+---------+--------
1 | 01 | 12345
2 | 02 | Null
3 | 03 | Null
4 | 05 | Null
6 | 01 | 67890
7 | 02 | Null
8 | 09 | Null
I need to make it look like this:
LinN | RecType | Value
-----+---------+--------
1 | 01 | 12345
2 | 02 | 12345
3 | 03 | 12345
4 | 05 | 12345
6 | 01 | 67890
7 | 02 | 67890
8 | 09 | 67890
I tried a cursor, Lead and Lag - but nothing is working for me.
Any idea/help will be highly appreciated

You can use a cumulative max:
select LinN, RecType, Value,
max(value) over (order by try_convert(int, LinN)) as imputed_value
from t;
You can incorporate this into an update:
with toupdate as (
select LinN, RecType, Value, max(value) over (order by LinN) as imputed_value
from t
)
update toupdate
set value = imputed_value;

Moderators, please close this discussion. I do not see any reason to keep it active.
Thank you everybody for your time.

Related

SQL create a conditional sequence

I want to create a conditional int field called Sequence for each group of IDs.
The value 1 is given to Sequence for the first occurrence of a condition, otherwise increment the last count by 1. There are finite list of values for the field condition as illustrated below.
For a new group of ID, Sequence should initialise and start counting from 1.
ID
Date
Condition
Seq
01
01Jun14
AAAAAAAAA
1
01
02Jun14
AAAAAAAAA
2
01
03Jun14
BBBBBBBBB
1
01
04Jun14
BBBBBBBBB
2
01
05Jun14
AAAAAAAAA
3
01
06Jun14
BBBBBBBBB
3
01
07Jun14
EEEEEEEEE
1
02
01Jun14
AAAAAAAAA
1
02
02Jun14
CCCCCCCCC
1
02
03Jun14
CCCCCCCCC
2
02
04Jun14
BBBBBBBBB
1
02
05Jun14
AAAAAAAAA
2
02
06Jun14
BBBBBBBBB
2
03
01Jun14
FFFFFFFFF
1
03
02Jun14
AAAAAAAAA
1
03
03Jun14
AAAAAAAAA
2
03
04Jun14
CCCCCCCCC
1
As pointed out in the comments by Squirrel, this is a job for row number
Basically
Seq = ROW_NUMBER() OVER (PARTITION BY ID, CONDITION ORDER BY DATE ASC)
If you need to incorporate this into your code while Insert statement, you'd do something like this
DECLARE #Seq INT
SELECT #Seq= ROW_NUMBER() OVER (PARTITION BY ID, CONDITION ORDER BY DATE ASC) FROM <yourtable> WHERE ID=#ID AND CONDITION= #condition
INSERT INTO <yourtable> VALUES
(#ID, #date, #condition, ISNULL(#Seq,1))
You need to use partition by condition, id in your row_number so that the row_numbers start at 1 for each combination of condition and id.
I have created a table with your required numbering so as to check that the calulated values are what you need.
select
ID,
d "Date" ,
Condition,
Seq seq_required,
row_number() over (partition by condition, id order by d) seq_calculated
from t
order by id, d
GO
ID | Date | Condition | seq_required | seq_calculated
-: | :--------- | :-------- | -----------: | -------------:
1 | 2014-06-01 | AAAAAAAAA | 1 | 1
1 | 2014-06-02 | AAAAAAAAA | 2 | 2
1 | 2014-06-03 | BBBBBBBBB | 1 | 1
1 | 2014-06-04 | BBBBBBBBB | 2 | 2
1 | 2014-06-05 | AAAAAAAAA | 3 | 3
1 | 2014-06-06 | BBBBBBBBB | 3 | 3
1 | 2014-06-07 | EEEEEEEEE | 1 | 1
2 | 2014-06-01 | AAAAAAAAA | 1 | 1
2 | 2014-06-02 | CCCCCCCCC | 1 | 1
2 | 2014-06-03 | CCCCCCCCC | 2 | 2
2 | 2014-06-04 | BBBBBBBBB | 1 | 1
2 | 2014-06-05 | AAAAAAAAA | 2 | 2
2 | 2014-06-06 | BBBBBBBBB | 2 | 2
3 | 2014-06-01 | FFFFFFFFF | 1 | 1
3 | 2014-06-02 | AAAAAAAAA | 1 | 1
3 | 2014-06-03 | AAAAAAAAA | 2 | 2
3 | 2014-06-04 | CCCCCCCCC | 1 | 1
db<>fiddle here
I think dense_rank() should do the trick.
select
ID,
[Date],
Condition,
dense_RANK() OVER(PARTITION by ID ORDER BY [Date]) as Seq
from Yourtable
SELECT ID,Condition,COUNT(con) as seq FROM "your table name" GROUP BY con
SELECT ID,Condition,COUNT(con) as seq FROM "your table name" where ID=1 GROUP BY con
desc:
1- for counting all type of Conditional in table
2- for counting each type of Conditional in each group of IDs

SELECT Top values for each records

I have been battling through this query/query design for sometime now and I thought it's time to ask the experts! Here's my table results:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
01 | Engaged | 11/4/2018 |
03 | Contacted | 16/4/2018 |
05 | Surveyed | 04/3/2017 |
05 | No Contact | 05/3/2017 |
How do I get it to return top/newest value for each ID:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
I've tried group by, TOP 1, Distinct and results still not what I wanted. Also, displaying the results by top 5% is won't do either as the ID can be more than just 3 types.
My QUERY below:
INSERT INTO TmpAllcomsEmployee ( StatusID, EmployeeID, CommunicationDate )
SELECT DISTINCT CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID,
Max(CommunicationLog.CommunicationDate) AS MaxOfCommunicationDate
FROM CommunicationLog RIGHT JOIN TmpAllcomsEmployee ON
CommunicationLog.EmployeeID = TmpAllcomsEmployee.EmployeeID
GROUP BY CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID
ORDER BY Max(CommunicationLog.CommunicationDate) DESC;
One method is a correlated subquery:
select cl.*
from CommunicationLog as cl
where cl.date = (select max(cl2.date)
from CommunicationLog as cl2
where cl2.EmployeeID = cl.EmployeeID
);
This gets the most recent record for each employee in CommunicationLog. You can join in the other table if you really need it. It does not seem unnecessary unless you are using it for filtering.

TSQL : conditional query

I have the following table :
| RoomID | OrderID | Occupancy | rn |
+--------+---------+-----------+----+
| 01 | 101 | Vacant | 1 |
| 01 | 102 | Occupied | 2 |
| 01 | 103 | Occupied | 3 |
| 01 | 104 | Vacant | 4 |
| 02 | 201 | Vacant | 1 |
| 02 | 202 | Occupied | 2 |
| 02 | 203 | Vacant | 3 |
| 03 | 301 | Vacant | 1 |
| 03 | 302 | Occupied | 2 |
| 03 | 303 | Occupied | 3 |
| 03 | 304 | Occupied | 4 |
| 04 | 401 | Occupied | 1 |
| 04 | 402 | Occupied | 2 |
| 04 | 403 | Vacant | 3 |
| 04 | 404 | Occupied | 4 |
I need to flag the RoomIDs where all of the following requirments are met as 'Yes' and if one or more requirements are not met as 'No':
when rn = 1 the Occupancy is vacant
When rn = 2 the Occupancy is Occupied
Any rn larger than 2 (3,4,5..) has an Occupancy of vacant
The result should look like the following:
| RoomID | OrderID |
+--------+---------+
| 01 | Yes |
| 02 | Yes |
| 03 | No |
| 04 | No |
I have an impression that this is easy but I cannot see it at the moment, thank you in advance for your help !
Builds on 'Yes' > 'No'
select RoomId,
min(case when rn<>2 and Occupancy='vacant'
or rn=2 and Occupancy='Occupied'
then 'Yes' else 'No' end) res
from myTable
group by RoomId
Using a CASE to calculate the rule for each row.
When the minimum of that rule (grouped by room_id) is 0, then at least 1 of them didn't follow the rule.
SELECT RoomID,
IIF(MIN(
CASE
WHEN rn <> 2 AND Occupancy = 'Vacant' THEN 1
WHEN rn = 2 AND Occupancy = 'Occupied' THEN 1
ELSE 0
END)=0,'No','Yes') as OccupancyRule
FROM RoomOccupancyTable
GROUP BY RoomID;
You can use Conditional Aggregation to check each condition.
with roomquery as (
select RoomId,
min(case when rn<>2 and Occupancy='vacant' then 1 else 0 end) cond1,
min(case when rn=2 and Occupancy='Occupied' then 1 else 0 end) cond2
from rooms r
group by RoomId)
select RoomId,
case when Cond1=1 and Cond2=1 then 'Yes' else 'No' end Status
from roomquery
Note: you can rewrite it and use only one condition or eve remove the CTE (with statement) altogether, but I believe this is more readable and maintainable.
I guess this will help you.
SELECT RoomID,
CASE WHEN ((rn = 1 OR rn > 2) AND Occupancy = 'Vacant') AND (rn = 2 AND Occupancy = 'Occupied') THEN 'Yes' ELSE 'No' END
FROM Table_Name
Here is another answer that counts the number of violations per RoomID in a subquery and then prints "yes" or "no" accordingly:
SELECT sub.roomid,
CASE WHEN sum(sub.orderid_no) IS NOT NULL THEN 'No'
ELSE 'Yes'
END AS orderID
FROM
(SELECT roomid,
CASE WHEN rn = 1 AND occupancy = 'occupied' THEN 1
WHEN rn = 2 AND occupancy = 'vacant' THEN 1
WHEN rn > 2 AND occupancy = 'occupied' THEN 1
END AS orderid_no
FROM T) sub
GROUP BY sub.roomid
Tested here: http://sqlfiddle.com/#!9/d9d467/14
Also, I think your output above is mistaken. According to your data, RoomID 01 should have OrderID "No"

Access Concatenating Values in a Query

I have a query, [Query1], with employee names, projects, days, months, and years.
In another query, [Query2], I take all the values and put them into a cross table. My rows are "Year, Month, Employee." My column is "Day." My values are Projects.
The problem is that for one date, there may be more than one project assigned to an employee.
When I attempt to put the projects as values into a table using IIf(Count(*)>0,[Project],""), I get an error because there may be more than one possible value for the project, and access doesn't know which one to choose.
I need a way to Concatenate the values if there is more than one Project.
Ex:
[Query1]
Bill | CC555 | 28 | 03 | 2014
Jim | CC999 | 29 | 03 | 2014
Jim | CC555 | 29 | 03 | 2014
John | CC555 | 29 | 03 | 2014
[Query2]
Year | Month | Employee | 1 | 2 | 3 | ... | 27 | 28 | 29 | 30 | 31
2014 | 03 | Bill | - | - | - | ... | - | CC555 | - | - | -
2014 | 03 | Jim | - | - | - | ... | - | - | CC555 + CC999 | - | -
2014 | 03 | John | - | - | - | ... | - | - | CC555 | - | -
Aside: [Query1] is dynamic and could have duplicate dates deleted or added to it, so [Query2] values must change accordingly.
one simple example,you have to make it dynamic,in real scenrio no need of table variable or CTE if using dynamic sql.i think no need of dynamic,just hard code from 1 to 31
;With CTE as
(
select 'Bill' Employee ,'CC555' codes,28 dd,03 mm ,2014 yrs union all
select 'Jim ','CC999', 29 , 03 , 2014 union all
select 'Jim ','CC555', 29 , 03 , 2014 union all
select 'John','CC555', 29 , 03 , 2014
)
select yrs,mm,Employee,isnull([28],'-')[28],[29],[30] from
(select Employee,dd,mm,yrs
,stuff((select ','+codes from cte b where b.Employee=a.Employee for xml path('')),1,1,'')codes
from cte a ) src
pivot (min(codes) for dd in([28],[29],[30])) pvt
By using the function given here allenbrowne.com/func-concat.html, and following the example given here http://www.access-programmers.co.uk/forums/showthread.php?t=234291, I was able to solve the problem.

SQL - How do I query for re-admissions in TSQL?

I'm trying to figure out how to query for readmissions on Server 2008r2. Here is the basic structure of the visit table. There are other fields but none that I thought would be helpful. One issue is that some of these may be transfers instead of discharges which I have no easy way to deduce but that issue can be ignored for now. I tried my hand at this but I guess my understanding of SQL needs more work. I tried to find any info I could online but none of the queries lead me to a useful conclusion or I just didn't understand. Any suggestions would be appreciated.
EDIT: Readmission is if a patient returns within 30 days of previous discharge.
+---------+--------+-----------------+-----------------+
| VisitID | UID | AdmitDT | DischargeDT |
+---------+--------+-----------------+-----------------+
| 12 | 2 | 6/17/2013 6:51 | 6/17/2013 6:51 |
| 16 | 3 | 6/19/2013 4:48 | 6/21/2013 13:35 |
| 18 | 3 | 6/11/2013 12:08 | 6/11/2013 12:08 |
| 21 | 3 | 6/12/2013 14:40 | 6/12/2013 14:40 |
| 22 | 3 | 6/13/2013 10:00 | 6/14/2013 12:00 |
| 25 | 2 | 6/11/2013 16:13 | 6/11/2013 16:13 |
| 30 | 1 | 6/20/2013 8:35 | 6/20/2013 8:35 |
| 31 | 7 | 6/13/2013 6:12 | 6/13/2013 6:12 |
| 34 | 3 | 6/12/2013 8:40 | NULL |
| 35 | 1 | 6/12/2013 8:52 | NULL |
| 38 | 2 | 6/12/2013 10:10 | 6/12/2013 10:10 |
+---------+--------+-----------------+-----------------+
Attempt at Code:
SELECT N2.*
FROM visitTable AS N1
INNER JOIN
visitTable AS N2 ON N1.UID = N2.UID
WHERE N1.EncounterID <> N2.EncounterID AND ( N2.AdmitDT BETWEEN N1.DischargeDT and DATEADD(DD,30, N1.DischargeDT))
Here's a start:
sqlfiddle
new fiddle
It gets each visit for each UID in order of admitDT, then pairs each visit with the next visit in that result. If the current admit date is between the last discharge date and 30 days from then, select it. There are some weird points though - UID 1 is shown to have been admitted on 6/12/2012 and never discharged, but then admitted again on 6/20/2013 and discharged the same day.
edit: restructured a bit to reduce the number of joins
WITH cte AS (
SELECT visitid,uid,dischargedt,admitdt,
row_number()over(partition BY uid ORDER BY admitdt) AS r
FROM t
)
SELECT
c1.visitid AS v1, c2.visitid AS v2,
c1.uid,
c1.dischargedt as [Discharged from first visit],
c2.admitdt as [Admitted to next visit]
FROM cte c1
INNER JOIN cte c2 ON c1.uid=c2.uid
WHERE c1.visitid<>c2.visitid
AND c1.r+1=c2.r
AND c2.admitdt BETWEEN c1.dischargedt AND dateadd(d,30,c1.dischargedt )
ORDER BY c1.uid
Results:
| V1 | V2 | UID | DISCHARGED FROM FIRST VISIT | ADMITTED TO NEXT VISIT |
|----|----|-----|-----------------------------|-----------------------------|
| 25 | 38 | 2 | June, 11 2013 16:13:00+0000 | June, 12 2013 10:10:00+0000 |
| 38 | 12 | 2 | June, 12 2013 10:10:00+0000 | June, 17 2013 06:51:00+0000 |
| 18 | 34 | 3 | June, 11 2013 12:08:00+0000 | June, 12 2013 08:40:00+0000 |
| 21 | 22 | 3 | June, 12 2013 14:40:00+0000 | June, 13 2013 10:00:00+0000 |
| 22 | 16 | 3 | June, 14 2013 12:00:00+0000 | June, 19 2013 04:48:00+0000 |
try this: (Show me the visits where the admission date is after discharge for another earlier visit by the same patient)
Select * From visits v
Where Exists (Select * From Visits
Where uid = v.uid
and v.AdmitDT > DischargeDT)
You have not explained any business rules so I'll take a guess. A readmission is when multiple UID appear, and it is every record except the first one
Here is another method using windowing functions.
SELECT VT.*
FROM visitTable VT
INNER JOIN
(
SELECT VisitID, ROW_NUMBER() OVER (PARTITION BY UID ORDER BY AdmitDT) VisitCount
FROM visitTable
) RA
ON RA.VisitCount > 1 AND RA.VisitID = VT.VisitID