How to generate an automatic INSERT script to a table - sql-server

I have just started with SQL Server, I don't know if it is with a job, trigger or a procedure, in short, what I need that you can support me is in doing the following: in a database where I store the record of some requirements, which are associated to a state where they can be Completed or Closed, the requirements that are in the Completed state after one week (exactly 7 days) must automatically change status to Closed, but in addition to that I need you to perform the INSERT (automatic) of that record that was made, means that all the data in the row are inserted the same and the only thing that changes is the column that corresponds to state, which in this case would be finished.
The following is the query with which I obtain the records of the requirements longer than 7 days with the status Completed.
SELECT TK_DT_RECORDS.*
FROM TK_HD_TICKETS AS TICKETS
INNER JOIN TK_DT_RECORDS ON TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID
WHERE TK_DT_RECORDS.TK_DT_RECORDS_ID = (SELECT MAX (TK_DT_RECORDS_ID)
FROM TK_DT_RECORDS
WHERE TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID)
AND (TK_DT_RECORDS.TK_CT_STATUS_ID = 'TMN')
AND (TK_DT_RECORDS.ACTIVITY_DATE < DATEADD(DAY, 7, GETDATE()));
Until there I don't know how to perform the automatic INSERT into that table.
TK_CT_STATUS_ID corresponds to the TMN Status Identifier for Completed, CDO for Closed.
UPDATE:
WITH CTE AS
(
SELECT TK_DT_RECORDS.*
FROM TK_HD_TICKETS AS TICKETS
INNER JOIN TK_DT_RECORDS ON TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID
WHERE TK_DT_RECORDS.TK_DT_RECORDS_ID = (SELECT MAX (TK_DT_RECORDS_ID)
FROM TK_DT_RECORDS
WHERE TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID)
AND (TK_DT_RECORDS.TK_CT_STATUS_ID = 'TMN')
AND (TK_DT_RECORDS.ACTIVITY_DATE < DATEADD(DAY, 7, GETDATE()))
)
INSERT INTO TK_DT_RECORDS ([TK_DT_RECORDS_ID], [ACTIVITY_DATE], [CONTENT],[TK_HD_TICKETS_ID], [NOTE], [USER_UPDATE], [TK_CT_STATUS_ID], [TK_BT_EMPLOYEES_ID],[TK_CT_SERVICES_ID], [TK_CT_PRIORITIES_ID], [TK_CT_CATEGORIES_ID], TK_CT_SUBSERVICES_ID])
VALUES ..................;

You have done the hardest part of the work by generating a select query that returns the records that need to be updated. A simple way to turn it into an update statement is to leverage the concept of updatable common table expression, that SQL Server supports:
WITH CTE AS (
SELECT TK_DT_RECORDS.*
FROM TK_HD_TICKETS AS TICKETS
INNER JOIN TK_DT_RECORDS ON TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID
WHERE TK_DT_RECORDS.TK_DT_RECORDS_ID = (SELECT MAX (TK_DT_RECORDS_ID) FROM TK_DT_RECORDS
WHERE TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID )
AND (TK_DT_RECORDS.TK_CT_STATUS_ID = 'TMN')
AND (TK_DT_RECORDS.ACTIVITY_DATE < DATEADD(DAY, 7, GETDATE()))
)
UPDATE CTE SET TK_CT_STATUS_ID = 'CDO'
Edit
If you are looking for an insert statement instead, then you can use the INSERT ... SELECT ... syntax, like:
INSERT INTO TK_DT_RECORDS(
[TK_DT_RECORDS_ID],
[ACTIVITY_DATE],
[CONTENT],
[TK_HD_TICKETS_ID],
[NOTE],
[USER_UPDATE],
[TK_CT_STATUS_ID],
[TK_BT_EMPLOYEES_ID],
[TK_CT_SERVICES_ID],
[TK_CT_PRIORITIES_ID],
[TK_CT_CATEGORIES_ID],
[TK_CT_SUBSERVICES_ID]
)
SELECT
TK_DT_RECORDS.[TK_DT_RECORDS_ID],
TK_DT_RECORDS.[ACTIVITY_DATE],
TK_DT_RECORDS.[CONTENT],
TK_DT_RECORDS.[TK_HD_TICKETS_ID],
TK_DT_RECORDS.[NOTE],
TK_DT_RECORDS.[USER_UPDATE],
'CDO',
TK_DT_RECORDS.[TK_BT_EMPLOYEES_ID],
TK_DT_RECORDS.[TK_CT_SERVICES_ID],
TK_DT_RECORDS.[TK_CT_PRIORITIES_ID],
TK_DT_RECORDS.[TK_CT_CATEGORIES_ID],
TK_DT_RECORDS.[TK_CT_SUBSERVICES_ID]
FROM TK_HD_TICKETS AS TICKETS
INNER JOIN TK_DT_RECORDS
ON TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID
WHERE
TK_DT_RECORDS.TK_DT_RECORDS_ID = (
SELECT MAX (TK_DT_RECORDS_ID)
FROM TK_DT_RECORDS
WHERE TICKETS.TK_HD_TICKETS_ID = TK_DT_RECORDS.TK_HD_TICKETS_ID
)
AND (TK_DT_RECORDS.TK_CT_STATUS_ID = 'TMN')
AND (TK_DT_RECORDS.ACTIVITY_DATE < DATEADD(DAY, 7, GETDATE()))
Please note that this will only work if TK_CT_STATUS_ID is part of all unique keys of your table (including the primary key); otherwise you will get key constraint error when trying to insert new records.

You don't need a cte for this. It is just an update statement. I changed up your query a bit to utilize aliases. When everything is in all upper case it is so difficult to read.
update r
set TK_CT_STATUS_ID = 'CDO'
FROM TK_HD_TICKETS AS t
INNER JOIN TK_DT_RECORDS r ON t.TK_HD_TICKETS_ID = r.TK_HD_TICKETS_ID
WHERE r.TK_DT_RECORDS_ID = (
SELECT MAX(r2.TK_DT_RECORDS_ID)
FROM TK_DT_RECORDS r2
WHERE t.TK_HD_TICKETS_ID = r2.TK_HD_TICKETS_ID
)
AND r.TK_CT_STATUS_ID = 'TMN'
AND r.ACTIVITY_DATE < DATEADD(DAY, 7, GETDATE());

Related

SQL Server ISNULL not working in multi table selection

I'm very new to SQL server and I'm trying to get the maximum price of an item based on the update of table and if is null to replace the null able value with zero.
Here is what I did:
DECLARE #itemid BIGINT
SELECT
(SELECT ISNULL(MAX(ITEM_SUPPLIER_PRICE.Price), 0.00)
FROM ITEM_SUPPLIER_PRICE
WHERE (ITEM_SUPPLIER_PRICE.item_id = 7)) AS price,
itemunits.unit_id,
itemunits.unit_name
FROM
ITEM_SUPPLIER_PRICE
INNER JOIN
Items ON ITEM_SUPPLIER_PRICE.item_id = Items.Item_id
INNER JOIN
itemunits ON Items.Item_unit_id = itemunits.unit_id
WHERE
(Items.Item_id = 7)
GROUP BY
itemunits.unit_id, itemunits.unit_name,
ITEM_SUPPLIER_PRICE.update_date
ORDER BY
ITEM_SUPPLIER_PRICE.update_date DESC;
I think you're just looking for the max price in the group. Since prices probably can't be negative, the second option below should be equivalent but I throw it in just in case the problem is there.
SELECT
COALESCE(MAX(isp.Price), 0.00) AS price1,
MAX(COALESCE(isp.Price, 0.00)) AS price2,
iu.unit_id,
iu.unit_name
FROM ITEM_SUPPLIER_PRICE isp
INNER JOIN Items i ON i.item_id = isp.Item_id
INNER JOIN itemunits iu ON iu.unit_id = i.Item_unit_id
WHERE i.Item_id = 7
GROUP BY
iu.unit_id,
iu.unit_name,
isp.update_date
ORDER BY isp.update_date desc;

SQL: Find MIN but greater than a MAX

I am working with task history and trying to find two dates attached to the same record: 1) Most recent time a task was approved (max approve); 2)The first submitted date after said approval.
Here is what I have so far:
Select
a.assn_uid,
max(b.ASSN_TRANS_DATE_ENTERED) as LastApprove,
e.LastSubmitted
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] a
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] b
on a.ASSN_TRANS_UID = b.ASSN_TRANS_UID
join (select c.assn_uid,
min(d.ASSN_TRANS_DATE_ENTERED) as LastSubmitted
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] c
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] d
on c.ASSN_TRANS_UID = d.ASSN_TRANS_UID
where c.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and d.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 0
group by c.assn_uid ) e
on e.ASSN_UID = a.ASSN_UID
where a.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and b.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 1
group by a.assn_uid, e.LastSubmitted
This is close, however, it gives me the first time ever that the task was submitted. I am sure that I need to use another subquery, I just dont know how to reference a column within the same result.
Here is the task history. Highlighted are the two dates I am trying to show:
I don't know that I could wade through your query in any reasonable amount of time, but to get the row after a particular row, you'd need to do something like this:
create table #submissions (
ID int,
DateAdded datetime,
SubmissionType nvarchar(100)
)
insert #submissions values
(1, '2010-01-01', 'first ever'),
(1, '2010-01-02', 'second'),
(1, '2010-01-03', 'third'),
(1, '2010-01-04', 'approve'),
(1, '2010-01-05', 'first after approve'),
(1, '2010-01-06', 'second after approve'),
(1, '2010-01-07', 'third after approve')
declare #lastApprovalDate datetime
select #lastApprovalDate = MAX(DateAdded)
from #submissions
where
SubmissionType = 'approve'
declare #firstAfterApprovalDate datetime
select #firstAfterApprovalDate = MIN(DateAdded)
from #submissions
where
DateAdded > #lastApprovalDate
select *
from #submissions
where
DateAdded = #firstAfterApprovalDate
drop table #submissions
In general, get the last approval date using MAX(), then get the first date after that date using MIN() where DateAdded > that max, and then select the row at that date. I added Top 1, just in case there happen to be multiple rows at that time. Not sure if that's possible in your data, but just to be safe.
With some help, we figured out we needed an additional min wrapped around the query.
SELECT
final.assn_uid,
final.LastApprove,
min(final.SubmissionDate) FirstSubmitted
FROM
(Select
a.assn_uid,
max(b.ASSN_TRANS_DATE_ENTERED) as LastApprove,
e.SubmittedDates SubmissionDate
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] a
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] b
on a.ASSN_TRANS_UID = b.ASSN_TRANS_UID
join (select c.assn_uid,
(d.ASSN_TRANS_DATE_ENTERED) as SubmittedDates
FROM [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS] c
inner join [PRJDEV_ProjectWebApp].[pub].[MSP_ASSIGNMENT_TRANSACTIONS_COMMENTS] d
on c.ASSN_TRANS_UID = d.ASSN_TRANS_UID
where c.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and d.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 0
) e
on e.ASSN_UID = a.ASSN_UID
where a.ASSN_UID = '499879BC-28B2-E411-8B0A-00059A3C7A00'
and b.[ASSN_TRANS_COMMENT_TYPE_ENUM] = 1
and e.SubmittedDates > b.ASSN_TRANS_DATE_ENTERED
group by a.assn_uid, e.SubmittedDates) Final
GROUP BY
final.assn_uid,
final.LastApprove

How to apply order by on Update?

I am trying to update values in Temporary table but before update i want to order by the records on the basis of date.
UPDATE INS
set ins.PrefferedEmail = IC.CntcInfoTxt
From #Insured INS
Inner Join InsuredContact IC
on IC.InsuredId = INS.Insuredid and IC.ExpDt < Getdate() And (INS.InsuredStatus = 'Expired' or INS.InsuredStatus = 'Merged')
Where IC.CntcTypeCd = 'EML' and IC.InsuredId = #InsuredId and MAX(IC.ExpDt) ExpDt
I want to update on the basis of this column IC.ExpDt
Thanks in advance
I think you are confusing an UPDATE with SELECT(ing) the correct data to update with.
I solved this problem with a common table expression (cte) and the rank() function. The cte is a nice way to get a sub-query results. The rank is needed to find the most recent contact info.
-- 1 - Get id, contact text, expired date, with a rank by expired date
-- 2 - Join with table to update, select rank = 1
;
WITH cteRecentContactInfo
AS
(
SELECT
ic.InsuredId,
ic.CntcInfoTxt,
ic.ExpDt,
RANK() OVER (ORDER BY ic.ExpDt DESC) as RankByDt
FROM
InsuredContact as ic
WHERE
ic.CntcTypeCd = 'EML' and ic.ExpDt < getdate()
)
UPDATE ins
FROM #Insured ins INNER JOIN cteRecentContactInfo rci
ON ins.Insuredid = rci.Insuredid and ins.ExpDt = rci.ExpDt
WHERE
(ins.InsuredStatus = 'Expired' OR ins.InsuredStatus = 'Merged') AND
rci.RankByDt = 1
Update and sorting doesn't work that way. The rows are not necessarily stored in any particular order, so sorting and updating are completely independent.
If you only want to update based on MAX(ExpDt) you need a subquery that pulls that up.
UPDATE INS
SET INS.PrefferedEmail = tempOutside.CntcInfo
FROM (SELECT IC.CntcInfo,IC.InsuredID FROM
InsuredContact IC INNER JOIN
(SELECT MAX(IC.ExpDt) AS MaxExpDt,IC.InsuredID
FROM IC
WHERE IC.ExpDt < Getdate()
AND IC.CntcTypeCd = 'EML'
GROUP BY IC.InsuredID) AS tempInside
ON tempInside.InsuredID = IC.InsuredID
AND IC.ExpDt = tempInside.MaxExpDt) AS tempOutside
INNER JOIN INS ON tempOutside.InsuredID = INS.InsuredId
WHERE (INS.InsuredStatus = 'Expired' OR INS.InsuredStatus = 'Merged')
AND INS.InsuredID = #InsuredID
On unrelated notes, for the good of whoever is doing maintenance on your code you might want to consider fixing the spelling errors (e.g. should be Preferred instead of 'Preffered') and giving the tables more meaningful names. Also since you're only working with one ID from #InsuredID you could simplify the code and remove an inner join or two but what I have should work for updating several records at once not just the one selected by #InsuredID.
Thanks for your time and comments. I have done this and its working fine
UPDATE INS
set ins.PrefferedEmail = ICC.CntcInfoTxt
From #Insured INS
Inner Join
(
SELECT
InsuredId,
CntcInfoTxt,
CntcTypeCd
From InsuredContact ICC
Where ExpDt = (select MAX(ExpDt) from InsuredContact where ExpDt < GETDATE() and CntcTypeCd = 'EML' and InsuredId = 10)
) As ICC
on ICC.InsuredId = INS.InsuredId And (INS.InsuredStatus = 'Expired' or INS.InsuredStatus = 'Merged')
Where ICC.InsuredId = #InsuredId

checking existence of a row before doing a SELECT INTO (SQL Server)

I have a SQL statement I'd like to amend. As it stands now I'm running a simple SELECT INTO but I'd like to modify it so only records that don't exist in the destination table (as determined by my criteria) are appended.
Here's my initial statement:
SELECT b.BallotID, m.MeetingDate
INTO StagingTable
FROM Ballot INNER JOIN Meeting on b.MeetingID = m.MeetingID
WHERE b.LastModifiedDate < '01-01-2010' AND ( b.BallotType = 'Agenda Vote' AND m.MeetingDate < GETDATE())
I'd like to change things so that the StagingTable is populated only when the ballot doesn't already exist. Is this an acceptable way of going about it, or are there better alternatives?
SELECT b.BallotID, m.MeetingDate
INTO StagingTable
FROM Ballot INNER JOIN Meeting on b.MeetingID = m.MeetingID
WHERE b.LastModifiedDate < '01-01-2010' AND ( b.BallotType = 'Agenda Vote' AND m.MeetingDate < GETDATE())
AND NOT EXISTS(SELECT 1 from StagingTable where BallotID = b.BallotID)) )
Your technique looks good except that the SELECT...INTO syntax is used to create a brand new table. Instead, you'd want to use the code below to add rows to an existing table:
INSERT INTO StagingTable
(BallotID, MeetingDate)
SELECT b.BallotID, m.MeetingDate
FROM Ballot b
INNER JOIN Meeting m
on b.MeetingID = m.MeetingID
WHERE b.LastModifiedDate < '01-01-2010'
AND (b.BallotType = 'Agenda Vote' AND m.MeetingDate < GETDATE())
AND NOT EXISTS(SELECT 1 from StagingTable where BallotID = b.BallotID)
SELECT INTO creates a new table rather than Insert data in to an existing table. Because of this I would check if the table exists if it does then drop the table before running your existing SQL. The will ensure that the StagingTable is dropped and recreated each time.
IF OBJECT_ID('StagingTable','U') IS NOT NULL
BEGIN
DROP TABLE StagingTable
END
SELECT b.BallotID, m.MeetingDate
INTO StagingTable
FROM Ballot INNER JOIN Meeting on b.MeetingID = m.MeetingID
WHERE b.LastModifiedDate < '01-01-2010' AND ( b.BallotType = 'Agenda Vote'
AND m.MeetingDate < GETDATE())
If you want to add rows to the existing table then you should use INSERT INTO as per Joe Stefanelli answer.

Use SQL to count cases in a certain state at a certain time

I need to develop a query that will count the total number of 'open' cases per month.
I have a 'cases' table with an id and a name, and a 'state_changes' table with a datetime column, a caseid column and a state.
How can I calculate the number of cases in each month that have a record with state 'open' in the past, but without a corresponding record with state closed?
I'm using SQL server 2000.
This should get you close (T-SQL):
SELECT
MONTH(s.casedate) m,
YEAR(s.casedate) y,
COUNT(DISTINCT c.caseid) count_cases
FROM
cases c
INNER JOIN state_changes s ON s.caseid = c.caseid
WHERE
s.state = 'open' /* "with state 'open'" */
AND s.casedate < GETDATE() /* "in the past" */
AND NOT EXISTS ( /* "without corresp. record with state 'closed'" */
SELECT 1 FROM state_changes i WHERE i.caseid = s.caseid AND i.state = 'closed'
)
GROUP BY
MONTH(s.casedate),
YEAR(s.casedate)
EDIT: To make a statistic over all twelve months (independent of actual cases existing in these months) you need a small helper table (let's call it month), that contains nothing but one column (let's call that month as well) with numbers from 1 to 12. Then you join against it:
SELECT
m.month,
COUNT(DISTINCT c.caseid) count_cases
FROM
cases c
INNER JOIN state_changes s ON s.caseid = c.caseid
LEFT JOIN month m ON m.month = MONTH(s.casedate)
WHERE
s.state = 'open'
AND YEAR(c.createddate) = YEAR(GETDATE()) /* whatever */
AND NOT EXISTS (
SELECT 1 FROM state_changes i WHERE i.caseid = s.caseid AND i.state = 'closed'
)
GROUP BY
m.month
ORDER BY
m.month
Create a query of the state changes tables for open events and one for close events.
Create a query that does an outer join of the open to the closed on the case ID returning the case ID from both queries
Query the latter query result for rows where the ID from the "close" event query is null
Count the number of rows in the latter query result.
Something very roughly like (off the top of my head, without correction):
SELECT COUNT (T1.CaseID) FROM (SELECT T1.CaseID AS T1_CaseID, T2.CaseID AS T2_CaseID
FROM ((SELECT CaseID FROM state_changes WHERE state = 'open' AND timestamp BETWEEN 1-Jan-09 AND 30-Jan-09) AS T1 OUTER JOIN (SELECT CaseID FROM state_changes WHERE state = 'closed' AND timestamp BETWEEN 1-Jan-09 AND 30-Jan-09) AS T2 ON T1.CaseID = T2.CaseID)) WHERE T2_CaseID = NULL

Resources