Update a Table Based on Count from Another Table - sql-server

I am trying to do a COUNT against a table using a date range, from another table. The count has to also match with a reference number, here's the data format:
[Rev Old New] (Table 1)
Id Start Finish Amount Calls
41 2018-01-01 2018-06-01 111.01
[Calls] (Table 2)
Id Date Amount
3 2018-05-05 12.1
41 2018-01-03 11.7
41 2018-06-11 12.9
I am quite new to MS SQL so apologies for my rather basic knowledge!
So, I want the count of rows in [Calls], where the Date is between the Start and Finish dates in [Rev Old New] and the ID is the same in both tables (it's a client ref)
I want to UPDATE [Rev Old New] with this value in [Calls]
Here's what I have so far, not working and probably nowhere near the right syntax!
UPDATE [Insight].[dbo].[Rev Old New]. t2
SET [Calls] =
(SELECT COUNT(CASE WHERE t1.Date BETWEEN t2.[Start] AND t2.[Finish])
FROM [Insight].[dbo].[Calls] t1
WHERE t1.[Id] = t2.[Id])
The error I get is this:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 't2'.
Msg 156, Level 15, State 1, Line 3
Incorrect syntax near the keyword 'WHERE'.

You don't need the CASE statement, a simple WHERE will suffice:
UPDATE [Insight].[dbo].[Rev Old New]
SET [Rev Old New].[Calls] = (SELECT COUNT(*) FROM [Insight].[dbo].[Calls] t1
WHERE t1.Date BETWEEN [Rev Old New].[Start] AND [Rev Old New].[Finish])

this may help
CREATE TABLE #RevOldNew(Id BIGINT, Start DATETIME, Finish DATETIME, Amount BIGINT, Calls INT)
CREATE TABLE #Calls(Id BIGINT,[Date] DATETIME, AMOUNT BIGINT)
INSERT INTO #RevOldNew
SELECT 1,'2018-06-01','2018-06-15',NULL,NULL UNION ALL
SELECT 1,'2018-07-16','2018-07-31',NULL,NULL UNION ALL
SELECT 1,'2018-08-01','2018-08-15',NULL,NULL UNION ALL
SELECT 1,'2018-08-16','2018-08-31',NULL,NULL UNION ALL
SELECT 2,'2018-07-01','2018-07-15',NULL,NULL UNION ALL
SELECT 2,'2018-08-01','2018-08-15',NULL,NULL UNION ALL
SELECT 2,'2018-08-16','2018-08-31',NULL,NULL UNION ALL
SELECT 3,'2018-07-16','2018-07-31',NULL,NULL UNION ALL
SELECT 3,'2018-08-01','2018-08-15',NULL,NULL UNION ALL
SELECT 3,'2018-08-16','2018-08-31',NULL,NULL
INSERT INTO #Calls
SELECT 1,'2018-07-16',23 UNION ALL
SELECT 1,'2018-07-21',534 UNION ALL
SELECT 1,'2018-07-28',456 UNION ALL
SELECT 1,'2018-08-02',43 UNION ALL
SELECT 1,'2018-08-11',565 UNION ALL
SELECT 1,'2018-08-20',56 UNION ALL
SELECT 2,'2018-07-05',576 UNION ALL
SELECT 2,'2018-08-22',54 UNION ALL
SELECT 2,'2018-08-29',676 UNION ALL
SELECT 3,'2018-07-17',32 UNION ALL
SELECT 3,'2018-08-15',43
;with cte
As (
SELECT r.id,r.Start,r.Finish, SUM(c.AMOUNT) Amount, COUNT(c.id) calls
FROM #RevOldNew r
LEFT JOIN #Calls c on r.id=c.id and c.Date between r.Start and r.Finish
Group by r.id,r.Start,r.Finish
)
UPDATE r
SET r.Amount=c.Amount,
r.Calls=c.calls
FROM #RevOldNew r
JOIN cte c on c.id=r.id and c.Start=r.Start and c.Finish=r.Finish
SELECT * from #RevOldNew
DROP TABLE #RevOldNew
DROP TABLE #Calls

First you should avoid spaces in table names. It's not a good practice.
Then a query which solves your problem is :
update [Rev Old New]
set Calls=(select count(*) from Calls where [Rev Old New].id = Calls.id and Calls.date >= [Rev Old New].Start and Calls.date <= [Rev Old New].Finish)
where
select count(*) from Calls where [Rev Old New].id = Calls.id and Calls.date >= [Rev Old New].Start and Calls.date <= [Rev Old New].Finish
count the lines from Calls with the id in [Rev Old New] with date in Calls between Finish and Start (included) in [Rev Old New]
I hope this helps.

Related

SQL stored procedure for picking a random sample based on multiple criteria

I am new to SQL. I looked for all over the internet for a solution that matches the problem I have but I couldn't find any. I have a table named 'tblItemReviewItems' in an SQL server 2012.
tblItemReviewItems
Information:
1. ItemReviewId column is the PK.
2. Deleted column will have only "Yes" and "No" value.
3. Audited column will have only "Yes" and "No" value.
I want to create a stored procedure to do the followings:
Pick a random sample of 10% of all ItemReviewId for distinct 'UserId' and distinct 'ReviewDate' in a given date range. 10% sample should include- 5% of the total population from Deleted (No) and 5% of the total population from Deleted (Yes). Audited ="Yes" will be excluded from the sample.
For example – A user has 118 records. Out of the 118 records, 17 records have Deleted column value "No" and 101 records have Deleted column value "Yes". We need to pick a random sample of 12 records. Out of those 12 records, 6 should have Deleted column value "No" and 6 should have Deleted column value "Yes".
Update Audited column value to "Check" for the picked sample.
How can I achieve this?
This is the stored procedure I used to pick a sample of 5% of Deleted column value "No" and 5% of Deleted column value "Yes". Now the situation is different.
ALTER PROC [dbo].[spItemReviewQcPickSample]
(
#StartDate Datetime
,#EndDate Datetime
)
AS
BEGIN
WITH CTE
AS (SELECT ItemReviewId
,100.0
*row_number() OVER(PARTITION BY UserId
,ReviewDate
,Deleted
order by newid()
)
/count(*) OVER(PARTITION BY UserId
,Reviewdate
,Deleted
)
AS pct
FROM tblItemReviewItems
WHERE ReviewDate BETWEEN #StartDate AND #EndDate
AND Deleted in ('Yes','No')
AND Audited='No'
)
SELECT a.*
FROM tblItemReviewItems AS a
INNER JOIN cte AS b
ON b.ItemReviewId=a.ItemReviewId
AND b.pct<=6
;
WITH CTE
AS (SELECT ItemReviewId
,100.00
*row_number() OVER(PARTITION BY UserId
,ReviewDate
,Deleted
ORDER BY newid()
)
/COUNT(*) OVER(PARTITION BY UserId
,Reviewdate
,Deleted
)
AS pct
FROM tblItemReviewItems
WHERE ReviewDate BETWEEN #StartDate AND #EndDate
AND deleted IN ('Yes','No')
AND audited='No'
)
UPDATE a
SET Audited='Check'
FROM tblItemReviewItems AS a
INNER JOIN cte AS b
ON b.ItemReviewId=a.ItemReviewId
AND b.pct<=6
;
END
Any help would be highly appreciated. Thanks in advance.
This may assist you in getting started. My idea is, you create the temp tables you need, and load the specific data into the (deleted, not deleted etc.). You then run something along the lines of:
IF OBJECT_ID('tempdb..#tmpTest') IS NOT NULL DROP TABLE #tmpTest
GO
CREATE TABLE #tmpTest
(
ID INT ,
Random_Order INT
)
INSERT INTO #tmpTest
(
ID
)
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7 UNION ALL
SELECT 8 UNION ALL
SELECT 9 UNION ALL
SELECT 10 UNION ALL
SELECT 11 UNION ALL
SELECT 12 UNION ALL
SELECT 13 UNION ALL
SELECT 14 UNION ALL
SELECT 15 UNION ALL
SELECT 16;
DECLARE #intMinID INT ,
#intMaxID INT;
SELECT #intMinID = MIN(ID)
FROM #tmpTest;
SELECT #intMaxID = MAX(ID)
FROM #tmpTest;
WHILE #intMinID <= #intMaxID
BEGIN
UPDATE #tmpTest
SET Random_Order = 10 + CONVERT(INT, (30-10+1)*RAND())
WHERE ID = #intMinID;
SELECT #intMinID = #intMinID + 1;
END
SELECT TOP 5 *
FROM #tmpTest
ORDER BY Random_Order;
This assigns a random number to a column, that you then use in conjunction with a TOP 5 clause, to get a random top 5 selection.
Appreciate a loop may not be efficient, but you may be able to update to a random number without it, and the same principle could be implemented. Hope that gives you some ideas.

Compare previous date and current date and update the table on basis on condition

I want to update my attendance table on basis of the following condition.
NonWorking type is 1
If its previous day or next attendance type is Absent then I want to mark NonWorking type is LWP in DAOthers Column.
I think you can use LAG() and LEAD() here to peek at the preceding and proceeding values of the attendance type. Then, if one of those should be absent, mark the NonWorking column appropriately.
WITH cte AS (
SELECT *,
LAG(AttendanceType, 1, 'Present') OVER (ORDER BY ADate) AS lag_at,
LEAD(AttendanceType, 1, 'Present') OVER (ORDER BY ADate) AS lead_at
FROM yourTable
)
UPDATE cte
SET NonWorking = 1
WHERE lag_at = 'Absent' OR lead_at = 'Absent'
I am not sure whether you want an sql query to update existing data or a solution which is needed while making an entry.
Use below query to update existing data:
Update AttendanceTable set DaOthers =
(select top 1 'LWP' from AttendanceTable at1
where AttendanceTable.EmployeeId = at1.EmployeeId
and DATEADD(day, -1,AttendanceTable.ADate) = at1.ADate
and at1.NonWorking = 1)
Table befor executing above query:
Table after executing above query:
To update at the time of inserting record:
If you want to update while inserting data then you may need to set a variable first then use that variable while inserting. In the first query you need to use ADate and EmployeeID.The Nonworking is always 1.
DECLARE #DaOthers nvarchar(20) = (select top 1 'LWP' from AttendanceTable at
where DATEADD(day, 1, at.ADate) ='2017-02-04' and at.NonWorking = 1 and EmployeeId = 1)
insert into AttendanceTable
(NonWorking, ADate, AttendanceType, EmployeeId, DaOthers)
values
(0,'2017-02-04', 'Present', 1,#DaOthers)
With CTE as
(
SELECT *,
DATEADD(DAY, 1, Lag(ADate, 1,ADate)
OVER (PARTITION BY DAttendanceId ORDER BY ADate ASC)) AS EndDate
FROM tbl_DailyAttendance where EmployeeId = 1001 and AMonth = 2 and AYear = 2017 and AttendanceType = 'Absent' and NonWorking = 0
)
--select * from CTE
select * from tbl_DailyAttendance tda inner join CTE c on tda.ADate = c.EndDate where tda.EmployeeID = 1001 and tda.NonWorking = 1 order by tda.ADate
This is how i do for checking the conditions
since you hvn't provided sample data,so try to understand my query and correct if anything minor.
;WITH CTE as
(
select *
,isnull((select 1 from tbl_DailyAttendance tdb
where ((tdb.adate=DATEADD(day,-1,tda.adate))
or (tdb.adate=DATEADD(day,1,tda.adate)))
and attendancetype='Absent'
),0) NewnonWorkingType
from tbl_DailyAttendance tda
)
--Testing purpose
--select * from cte
update tda
set nonworking=b.NewnonWorkingType
,daOther=case when b.NewnonWorkingType=1 then 'LWP'
else null end
from tbl_DailyAttendance tda
inner join cte b on tda.id=b.id

Update previous row, get value from other row

I'm very new with T-SQL and I need some help. I have a table1. How I can do this process?
Should I use nested cursor or what? Need an advice on this.
Pls refer pic here -- http://i.stack.imgur.com/CHYIg.gif
Here is my code so far:
DECLARE #get_invckey datetime;
SET #get_invckey = '2013-04-09 13:30:43.537'
UPDATE table1
SET RUNTIME = #get_invckey
FROM
(
SELECT
DCREPORTTIME
FROM table1
WHERE
LOCATIONAME = 'MYQ01_PRNT_A_SP3'
AND EVENT LIKE '%RUN%'
) newdata
WHERE
LOCATIONAME = 'MYQ01_PRNT_A_SP3'
AND EVENT = 'MACHINE B STOPPED'
Not complete answer, for you question is not complex enough.
Just quick and simple example how this could be achieved.
Some sample data
DECLARE #Table table
( dcreporttime datetime, event_name varchar(55))
insert INTO #Table
SELECT '2013-04-09 13:34:01', 'RUNNING'
union
SELECT '2013-04-09 13:34:19', 'STOPPED'
union
SELECT '2013-04-09 13:34:29', 'RUNNING'
union
SELECT '2013-04-09 13:34:39', 'RUNNING'
union
SELECT '2013-04-09 13:35:19', 'STOPPED'
union
SELECT '2013-04-09 13:35:29', 'RUNNING'
union
SELECT '2013-04-09 13:35:39', 'RUNNING'
union
SELECT '2013-04-09 13:36:19', 'RUNNING'
union
SELECT '2013-04-09 13:37:19', 'STOPPED'
union
SELECT '2013-04-09 13:37:39', 'RUNNING'
And the query. It uses CTE (Common Table Expression) and Ranking functions:
;with cte as
(
SELECT RANK() OVER(ORDER by dcreporttime) as RankN, *
FROM #Table
)
select a.dcreporttime, a.event_name, a.dcreporttime, b.dcreporttime, DATEDIFF(ms, a.dcreporttime, b.dcreporttime) as runtime
from cte a
-- shift by Rank to compare with previous row
join cte b on a.RankN = b.RankN + 1
This simply you get time since previous event. I hope this could point you to solution. If don't, please be more specific in what you need :)
I have updated the view as follows:
create view [dbo].[cm] as
WITH cteMain
AS
(SELECT DCREPORTTIME,
ROW_NUMBER() OVER (ORDER BY DCREPORTTIME) AS rn,
RUNTIME,
[EVENT] AS EVENT
FROM
table1),
cte2 as (SELECT
sLeg.rn,
slead.DCREPORTTIME AS leadvalue,
sLeg.DCREPORTTIME AS lagvalue,
m.EVENT
FROM
cteMain AS m
LEFT OUTER JOIN cteMain AS sLead
ON sLead.rn = m.rn+1
LEFT OUTER JOIN cteMain AS sLeg
ON sLeg.rn = m.rn-1)
SELECT cte2.leadvalue, cte2.lagvalue, cte2.rn, cte2.EVENT
FROM cte2
Then, I revised the update query to:
update table1
set RUNTIME = DATEDIFF(ms, lagvalue, leadvalue)
FROM cm
where leadvalue=table1.DCREPORTTIME
and table1.EVENT='MACHINE RUNNING'
I used the first three rows of yours as sample data and this is what I see after the UPDATE:
Is this what you are looking for? I realize, by the way, that this can all be done without a view, but, I found this to be easier to work with, as far as taking on the problem step by step.
I based my query on a query I found at the following link:
Query to simulate Lead function in SQL Server 2008
See SQLFiddle at: SQLFiddle for Update previous row, get value from other row

SQL Query runs forever - SQL Server 2008

I have two Tables in two different databases
Database1 - Table1
Database2 - Table2
Table1 Columns: NimID,IDDate,Station
Table2 Columns: XilID,XilDate
Table1 Table2
NimID IDDate Station XilID XilDate
234 2011-04-21 HYD 234 2011-04-21
237 2011-04-21 CHN 208 2011-04-21
208 2011-04-21 HYD 209 2011-04-15
209 2011-04-15 DEL 218 2011-05-28
212 2011-03-11
I want to find out how many IDs in Table1 are not in Table2 where IDDate=XilDate='2011-04-21' group by Table1.Station .
I made the query below
select x.Station as Station,
count(distinct x.NimID) as Difference
from (
select a.NimID,
a.IDDate,
a.Station
from database1.dbo.table1 a
where left(cast(a.Date as date),11)='2011-04-21'
) as X, (
select b.XilID,
b.XILDate
from database2.dbo.Table2 b
where b.XilDate='2011-04-21'
) as Y
where x.NimID not in (y.XilID)
group by x.Station
But this query runs forever..
Please remember the tables are from different databases located on same server and Table1 contains 10,000,000 records and Table2 contains around 13,000,000 records
Please correct my query if wrong or suggest me the faster way
Thanks
DECLARE #date datetime;
SET #date = '20110421';
SELECT
Station,
Diff = COUNT(*)
FROM (
SELECT
a.NimID,
a.IDDate,
a.Station
FROM database1.dbo.table1 a
LEFT JOIN database2.dbo.table2 b ON a.NimID = b.XilID AND b.XilDate = #date
WHERE b.XilID IS NULL
AND a.IDDate >= #date
AND a.IDDate < DATEADD(day, 1, #date)
) s
GROUP BY Station
UPDATE
Actually, the above solution could be rewritten without subselects. The subselect is the result of trying some idea, which I've eventually discarded, but the subselect has remained for some unknown reason. Here's an identical solution with no subselects:
DECLARE #date datetime;
SET #date = '20110421';
SELECT
a.Station,
Diff = COUNT(*)
FROM database1.dbo.table1 a
LEFT JOIN database2.dbo.table2 b ON a.NimID = b.XilID AND b.XilDate = #date
WHERE b.XilID IS NULL
AND a.IDDate >= #date
AND a.IDDate < DATEADD(day, 1, #date)
GROUP BY a.Station
Try to avoid converting from datetime to varchar.
WHERE a.Date >= '2011-04-21'
AND a.Date < (CAST('2011-04-21' AS datetime) + 1)
Try the below - note that you appeared to be attempting to join the two tables to perform the 'not in' which would result in a very slow to produce and very wrong resultset.
Also, if IDDate is a DATETIME column then you'd be better of performing a range check e.g. (a.IDDate >= '2011-04-21' AND a.IDDate < '2011-04-22'). Thinking about it - if it's a text column in the format yyyy-MM-dd then a range check would also work - if it's a text column with mixed format dates then forget I mentioned it.
select x.Station as Station,
count(distinct x.NimID) as Difference
from (
select a.NimID,
a.IDDate,
a.Station
from database1.dbo.table1 a
where left(cast(a.IDDate as date),11)='2011-04-21'
) as X
where x.NimID not in (
select b.XilID
from database2.dbo.Table2 b
where b.XilDate='2011-04-21'
)
group by x.Station

Query To Get "Most Recent" Joining On Other Table With Date

I have a couple of tables and need to join them, but with a twist.
Table #GradeChange has Student IDs, the Effective Date of the grade change, and the Grade they were changed to ON that date. Table #EventOccurrence has events that occurred for that student on a certain date. I need to find what grade the student was in when the event occurred. This will be the most recent Grade from #GradeChange that occurred prior to the #EventOccurrence Effective Date. Students may have multiple EventOccurrences, and we can assume all students will have at least one #GradeChange entry with a date prior to their oldest event.
This is the DDL:
/* If the test table already exists, drop it */
IF OBJECT_ID('TempDB..#GradeChange','U') IS NOT NULL
DROP TABLE #GradeChange;
IF OBJECT_ID('TempDB..#EventOccurrence','U') IS NOT NULL
DROP TABLE #EventOccurrence;
/* Create first temp table */
CREATE TABLE #GradeChange
(
ID varchar(6),
EffectiveDate datetime,
Grade varchar(50)
);
/* Populate it */
INSERT INTO #GradeChange
(ID, EffectiveDate, Grade)
SELECT '678443','Jul 2 2009 11:30PM','Grade 3' UNION ALL
SELECT '678443','Jan 24 2007 2:40PM','Kindergarten - Half Day' UNION ALL
SELECT '678443','Jul 4 2007 11:09PM','Grade 1' UNION ALL
SELECT '678443','Jul 2 2008 11:35PM','Grade 2' UNION ALL
SELECT '718466','May 18 2009 11:50PM','Pre-Kindergarten' UNION ALL
SELECT '718466','Jul 2 2009 11:27PM','Kindergarten - Half Day' UNION ALL
SELECT '718466','Aug 27 2009 11:18PM','Pre-Kindergarten' UNION ALL
SELECT '718466','Jul 9 2010 11:18PM','Kindergarten - Half Day' UNION ALL
SELECT '718466','Aug 2 2010 11:14PM','Kindergarten';
/* Create 2nd temp table */
CREATE TABLE #EventOccurrence
(
ID varchar(6),
EventDate datetime
);
/* Populate it */
INSERT INTO #EventOccurrence
(ID, EventDate)
SELECT '718466','Nov 16 2010 12:00AM' UNION ALL
SELECT '718466','May 20 2009 12:00AM' UNION ALL
SELECT '678443','Dec 7 2007 12:00AM';
So the two tables would look like this:
And the expected results would look like this:
I've played with "MAX" and "MIN" and "OVER()" but can't quite get it right. I very much appreciate any help!
SELECT *
FROM #EventOccurrence eo
OUTER APPLY
(
SELECT TOP 1 Grade
FROM #GradeChange gc
WHERE gc.id = eo.id
AND gc.EffectiveDate <= eo.EventDate
ORDER BY
gc.EffectiveDate DESC
) gc
select eo.ID, eo.EventDate, gc.Grade
from #EventOccurrence eo
inner join #GradeChange gc
on eo.ID = gc.ID
and gc.EffectiveDate = (select max(gc.EffectiveDate)
from #GradeChange gc
where gc.ID = eo.ID
and gc.EffectiveDate <= eo.EventDate)
with merged (ID, DDate, Grade, pos) AS
(
select ID, DDate, Grade, ROW_NUMBER() over (order by ID, DDate) AS pos FROM (
select ID, EffectiveDate AS DDate, Grade FROM GradeChange
union
select ID, EventDate AS DDate, NULL FROM EventOccurrence
) sub
)
SELECT m1.ID, m1.DDate, m2.Grade FROM merged m1 LEFT OUTER JOIN merged m2 ON m1.pos = m2.pos+1 WHERE m1.Grade IS NULL

Resources