SQL Server 2000: need to return record ID from a previous record in current query - sql

I work on a help-desk and am doing some analysis of PC repair tickets.
I am needing to dump data from our call log system that returns history of tickets for issues on computers where they were recently repaired by another team. We are simply trying to improve QA on deployed machines and this data will help.
I have the query for the analysis of tickets, but I am wanting to return the ticket number of the last PC repair case.
My current query is as follows:
SELECT
CallLog.CallID,
CallLog.CustID,
Subset.Rep_num,
Subset.FirstName,
Subset.LastName,
CallLog.OpndetailCat,
CallLog.Tracker_Full,
CallLog.RecvdDate,
FROM
heatPrd.dbo.CallLog CallLog,
heatPrd.dbo.Subset Subset
WHERE
CallLog.CallID = Subset.CallID AND
CallLog.RecvdDate>='2015-10-01' AND
CallLog.OpnAreaCat='back from repair'
ORDER BY
CallLog.CallID DESC
This returns
CallID CustID Rep_num FirstName LastName OpndetailCat Tracker_Full
2182375 1234 Sarah Doe Missing Email Folde
2181831 1235 JENNIFER Doe ZOTHER
2180815 1236 123 Jason Smith ZOTHER
2180790 1237 124 DARCY Doe Wrong Proxy Config
2180787 1239 125 Jason Smith ZOTHER
I want to add a column to the query that would return something to the effect of
select max(callid)
from calllog
where calltype = 'in_for_service_pc' and custid = '1234'
where calltype = 'in_for_service_pc' resides on the CallLog table and custID would pull from the query result.
This is a lot of info so i hope my request is clear.
Disclaimer: Data resides in SQL Server 2000 so some of the newer commands may not work.

Something like this should be pretty close.
SELECT
cl.CallID,
cl.CustID,
s.Rep_num,
s.FirstName,
s.LastName,
cl.OpndetailCat,
cl.Tracker_Full,
cl.RecvdDate,
x.MaxCallID
FROM heatPrd.dbo.CallLog cl
JOIN heatPrd.dbo.Subset s ON cl.CallID = s.CallID
left join
(
select max(cl2.callid) as MaxCallID
, cl2.custid
from calllog cl2
where cl2.calltype = 'in_for_service_pc'
group by cl2.custid
) x on x.custid = cl.custid
WHERE cl.RecvdDate >= '2015-10-01' AND
cl.OpnAreaCat = 'back from repair'
ORDER BY cl.CallID DESC

Related

SQL - Remove duplicates after using a GROUP BY clause [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 10 months ago.
Let's say I had two tables that looked like this:
Prod_SerialNo
Prod_TestOnAt
Prod_AccountNo
SN0001
2021-04-08
045678
SN0001
2021-01-14
067891
SN0001
2021-11-29
091234
SN0002
2022-01-19
045678
SN0002
2020-07-30
045678
SN0002
2022-03-30
012345
SN0003
2022-04-01
078912
SN0003
2022-02-19
089123
SN0003
2022-03-18
023456
S_AccountNo
S_AccountType
S_AccountName
012345
Homeowner
Adam Smith
023456
Homeowner
Jeremy Chan
034567
Manufacturer
Anne Hudson
045678
Distributor
Barney Jones
056789
Distributor
Jasmine Coleman
067891
Homeowner
Christian Lewis
078912
Distributor
Heather Ogden
089123
Homeowner
Stephen Gray
091234
Distributor
Antony Newman
The Prod Table tabulates specific product tests by what serial number was used, when the product was tested, and who tested it. (There are other things in the table, including a primary key not shown here)
The S Table is a list of subscribers with a variety of information about them. S_AccountNo is the parent to Prod_AccountNo.
I want to query when the last test was performed for each Serial Number and what account name it was that performed the test, but I don't want multiple results (duplicates) for the same serial number. I have tried the following code:
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) AS "Last Time Tested",
S_AccountName
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
GROUP BY Prod_SerialNo, S_AccountName
ORDER BY Prod_SerialNo
However, the query ends up outputting the same serial number on multiple rows even though I ask for the max TestOnAt date and I group by serial number. What am I getting wrong?
I think there is no need to use Group by you can get result with Row_Number like this:
SELECT
t.Prod_SerialNo,
t.Prod_TestOnAt AS "Last Time Tested",
t.S_AccountName
FROM (
SELECT
Prod_SerialNo,
Prod_TestOnAt,
S_AccountName,
ROW_NUMBER() OVER (PARTITION BY Prod_SerialNo ORDER BY Prod_TestOnAt DESC) rw
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
) t
WHERE t.rw=1
ORDER BY t.Prod_SerialNo
You are grouping by Prod_SerialNo, S_AccountName so you will get duplicate Prod_SerialNo if multiple rows exist with that Prod_SerialNo and different S_AccountNames. You could do a MAX on Prod_TestOnAt and get that value with it's Prod_SerialNo, then join the result on the table to get your desired info using a subquery like so:
SELECT
p.[Prod_SerialNo],
max.[LastTimeTested],
s.[S_AccountName]
FROM PROD as p
INNER JOIN
(
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) as [LastTimeTested]
FROM Prod
GROUP BY [Prod_SerialNo]
) as max
on max.[Prod_SerialNo] = p.[Prod_SerialNo] and max.[LastTimeTested] = p.[Prod_TestOnAt]
INNER JOIN S as s
ON s.[S_AccountNo] = p.[Prod_AccountNo]
ORDER BY p.[Prod_SerialNo]
If you don't like the solution using ROW_NUMBER an alternative is to use CROSS APPLY to identify the last Prod_TestOnAt and the associated Prod_AccountNo.
SELECT DISTINCT p.Prod_SerialNo, ca.Prod_TestOnAt, s.S_AccountName
FROM Prod p
CROSS APPLY (SELECT TOP 1 Prod_TestOnAt, Prod_AccountNo
FROM Prod
WHERE Prod_SerialNo = p.Prod_SerialNo
ORDER BY Prod_TestOnAt DESC) ca
INNER JOIN S ON S.S_AccountNo = ca.Prod_AccountNo

Query only latest entry for each user

The goal of the following query is, to check whether a user has been terminated in the system in time. So there is a table that contains information about the system termination (how and when the user has been terminated) and one with the termination date of the user. Since there are three ways to terminate a user, some users have several termination entries. In the end, I only want to see the latest entry before their termination date if they have been terminated at all. All Date fields are INT fields.
Current Query:
Select
B.TerminationApproach,
B.SystemTerminationDate,
A.UserName,
A.LastName,
A.FirstName,
A.TerminationDate,
Case
When B.SystemTerminationDate <= A.TerminationDate Then 0
Else 1
End As EvalCheck
From A
Left Join B On B.User = A.UserName
Current Result:
TerminationApproach SystemTerminationDate TerminationDate UserNAme LastName FirstName EvalCheck
No profiles 20180301 20180226 AWALL Wall Aaron 1
Locally locked 20181027 20180226 AWALL Wall Aaron 1
Deleted 20180301 20180226 AWALL Wall Aaron 1
No profiles 20180301 20180301 CBLAIR Blair Carlos 0
Locally locked 20181027 20180301 CBLAIR Blair Carlos 1
No profiles 20180301 20180301 CBLAIR Blair Carlos 0
Then there is a third table which contains user activity. I need to map the results of my first query to the user activity, to see whether the user has performed changes after in the system after his termination date. The third table looks like this:
UserID Date Activity
AWALL 20180227 Table Change
So with my example, the end result of my query should look like this:
TerminationApproach SystemTerminationDate TerminationDate UserNAme LastName FirstName EvalCheck ActivityAfterTermination
No profiles 20180301 20180226 AWALL Wall Aaron 1 Yes
No profiles 20180301 20180301 CBLAIR Blair Carlos 0 No
Your question and your query are rather disconnected. It is not clear what columns represent a user or the date you care about.
But the basic idea is:
with t as (
<your query here>
)
select t.*
from (select t.*,
row_number() over (partition by UserId order by date desc) as seqnum
from t
) t
where seqnum = 1;

finding duplicate rows with different IDs based on multiple columns

please forgive me if my jargon is off. I'm still learning!
I just started using Teradata, and to be honest has been a lot of fun. however, I have hit a road block that has stumped me for a while.
I successfully selected a table from a database that looks like:
ID service date name
1 service1 1/5/15 john
2 service2 1/7/15 steve
3 service3 1/8/15 lola
4 service4 1/3/15 joan
5 service5 1/5/15 fred
6 service3 1/3/15 joan
7 service5 1/8/15 oscar
Now I want to search the data base again to find any duplicate IDs (example: to see if service service1 with date 1/5/15 with name john exists on another row with a different ID.)
At first, I did something like this:
SELECT ID, service, date, name
FROM table
WHERE table.service = ANY(service1, service2, service3, service4, service5, service3, service5)
AND table.date = ANY('1/5/15', '1/7/15, '1/8/15', '1/3/15', '1/5/15', '1/3/15', '1/8/15')
AND table.name = ANY('john', 'steve', 'lola', 'joan', 'fred', 'joan', 'oscar');
But this is giving me more rows than I wanted.
example:
ID service date name
92 service3 1/8/15 steve
is of no use to me since I am looking for IDs that have the same combination of service, date, and name as of any of the other IDs in the above table.
something like this would be favorable:
ID service date name
609 service3 1/8/15 lola
since it matches than of ID 3.
I was curious to see if it were possible to treat the three columns (service, date, name) as a vector and maybe select the rows that match it that way?
ex
......
WHERE (table.service, table.date, table.name) = ANY((service3,1/8/15,lola), (service1, 1/5/15, john), ...etc)
My Teradata is down right now, So I have yet to try the above example. Nevertheless, any thoughts/feedback is greatly appreciated!
The following query may be what you are trying to achieve. This selects IDs for which the combination of service, date, and name appears more than once.
SELECT t1.ID
FROM yourTable t1
INNER JOIN
(
SELECT service, date, name
FROM yourTable
GROUP BY service, date, name
HAVING COUNT(*) > 1
) t2
ON t1.service = t2.service AND
t1.date = t2.date AND
t1.name = t2.name
This is a simple task for a Windowed Aggregate:
SELECT *
FROM tab
QUALIFY
COUNT(*) OVER (PARTITION BY service, date, name) > 1
This counts the number of rows with the same combination of values (like Tim Biegeleisen's Derived Table) but unlike a Standard Aggregate it keeps all rows. The QUALIFY is a nice Teradata syntax extension to avoid a Derived Table.
Don't hardcode values in your query unless you absolutely have to. Instead, take the query you already wrote and join to that.
SELECT dupes.*
FROM (your query) yourquery
JOIN table dupes
ON yourquery.service = dupes.service
AND yourquery.date = dupes.date
AND yourquery.name = dupes.name

SQL Oracle - display values only once per column

I'm trying to format a select statement. The assignment specifies that it has to be formatted this way.
I have a database regarding a taxi service. I have to put together a view with the company name, passenger name, and taxi number. Easy. However, the output specifies that the company name should only appear once in the output, at the top of it's own group. So I have:
CREATE VIEW TAXITRIPS(COMPANYNAME, PASSENGERNAME, TAXI#) AS
(SELECT COMPANY.NAME, BOOKING.NAME, VEHICLES.TAXI#
FROM BOOKING JOIN VEHICLES ON BOOKING.TAXI# = VEHICLES.TAXI#
RIGHT OUTER JOIN COMPANY ON VEHICLES.NAME = COMPANY.NAME);
The right outer join is so that companies with no booking recorded are still displayed. If I now run:
SELECT * FROM TAXITRIPS ORDER BY COMPANYNAME ASC;
It will give me something like
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
PREMIER CABS TIM 2169
SILVER SERVICE DAVE 18579
SILVER SERVICE TIM 18124
SILVER SERVICE AARON 18917
No result for legion cabs, all field displayed, et cetera. Assignment specification says it has to look like this.
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
TIM 2169
SILVER SERVICE DAVE 18579
TIM 18124
AARON 18917
The company name should only be displayed on its first row. DISTINCT is not helping. Any advice?
Normally, you would do this at the application layer, because the result set relies on the ordering of the rows -- a bad thing in SQL.
But you can do it as:
SELECT (CASE WHEN ROW_NUMBER() OVER (PARTITION BY c.NAME ORDER BY v.TAXI#) = 1
THEN c.NAME
END) as CompanyName, b.NAME, v.TAXI#
FROM COMPANY c LEFT JOIN
VEHICLES v
ON v.NAME = c.NAME LEFT JOIN
BOOKING b
ON b.TAXI# = v.FLIGHT#
ORDER BY c.name, v.taxi#;
Note: I rearranged the joins to be LEFT JOINs. Most people find that easier to follow than RIGHT JOINs.

GROUP BY and aggregate function query

I am looking at making a simple leader board for a time trial. A member may perform many time trials, but I only want for their fastest result to be displayed. My table columns are as follows:
Members { ID (PK), Forename, Surname }
TimeTrials { ID (PK), MemberID, Date, Time, Distance }
An example dataset would be:
Forename | Surname | Date | Time | Distance
Bill Smith 01-01-11 1.14 100
Dave Jones 04-09-11 2.33 100
Bill Smith 02-03-11 1.1 100
My resulting answer from the example above would be:
Forename | Surname | Date | Time | Distance
Bill Smith 02-03-11 1.1 100
Dave Jones 04-09-11 2.33 100
I have this so far, but access complains that I am not using Date as part of an aggregate function:
SELECT Members.Forename, Members.Surname, Min(TimeTrials.Time) AS MinOfTime, TimeTrials.Date
FROM Members
INNER JOIN TimeTrials ON Members.ID = TimeTrials.Member
GROUP BY Members.Forename, Members.Surname, TimeTrials.Distance
HAVING TimeTrials.Distance = 100
ORDER BY MIN(TimeTrials.Time);
IF I remove the Date from the SELECT the query works (without the date). I have tried using FIRST upon the TimeTrials.Date, but that will return the first date which is normally incorrect.
Obviously putting the Date as part of the GROUP BY would not return the result set that I am after.
Make this task easier on yourself by starting with a smaller piece of the problem. First get the minimum Time from TimeTrials for each combination of MemberID and Distance.
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance;
Assuming that SQL is correct, use it in a subquery which you join back to TimeTrials again.
SELECT tt2.*
FROM
TimeTrials AS tt2
INNER JOIN
(
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance
) AS sub
ON
tt2.MemberID = sub.MemberID
AND tt2.Distance = sub.Distance
AND tt2.Time = sub.MinOfTime
WHERE tt2.Distance = 100
ORDER BY tt2.Time;
Finally, you can join that query to Members to get Forename and Surname. Your question shows you already know how to do that, so I'll leave it for you. :-)