I m having the data like this...
with cte as
(select *, rn = row_number() over (partition by empid order by trtime)
from [10.xx.xx.xx].[dbName].dbo.[tableName] where empid='00ec2137' and trdate='01/13/2014'
)
select i.empid,i.trdate, i.trtime InTime, o.trtime OutTime
from cte i
inner join cte o on i.empid = o.empid
and i.rn = o.rn - 1
where i.InOUt = 1
and o.InOUt = 2
order by i.empid,i.rn
InOut 1 - "In timing" and 2 - "out timing". I want the data to be ordered like In Timing and Out Timing in a separate column. I m using the above query in SQL 2012 to display the data like below
Getting Output
Expected Output
In the output it displayed the first two rows only. As there is no Out timing 2 in third row, third row is not displayed. Please suggest me how to correct the code.
simple I got this by modifying the inner join into left join and removed o.InOUt = 2 in where condtion
I think the problem is with the where clause. Try this where clause instead:
where (i.InOUt = 1)
and (o.InOUt = 2 or o.InOUt is null)
this will bring when the user has logged out or still logged in.
Related
I have the following query returning the data as shown below. But I need to exclude the rows with MODIFIEDDATETIME shown in red as they have a lower time stamp by COMMITRECID. As depicted in the data, there may be multiple rows with the max time stamp by COMMITRECID.
SELECT REQCOMMIT.COMMITSTATUS, NOTEHISTORY.NOTE, NOTEHISTORY.MODIFIEDDATETIME, NOTEHISTORY.COMMITRECID
FROM REQCOMMIT INNER JOIN NOTEHISTORY ON REQCOMMIT.RECID = NOTEHISTORY.COMMITRECID
WHERE REQCOMMIT.PORECID = 1234
Here is the result of the above query
The desired result is only 8 rows with 5 in Green and 3 in Black (6 in Red should get eliminated).
Thank you very much for your help :)
Use RANK:
WITH CTE AS
(
SELECT R.COMMITSTATUS,
N.NOTE,
N.MODIFIEDDATETIME,
N.COMMITRECID,
RN = RANK() OVER(PARTITION BY N.COMMITRECID ORDER BY N.MODIFIEDDATETIME)
FROM REQCOMMIT R
INNER JOIN NOTEHISTORY N
ON R.RECID = N.COMMITRECID
WHERE R.PORECID = 1234
)
SELECT *
FROM CTE
WHERE RN = 1;
As an aside, please try to use tabla aliases instead of the whole table name in your queries.
*Disclaimer: You said that you wanted the max date, but the selected values in your post were those with the min date, so I used that criteria in my answer
This method just limits your history table to those with the MINdate as you described.
SELECT
REQCOMMIT.COMMITSTATUS,
NOTEHISTORY.NOTE,
NOTEHISTORY.MODIFIEDDATETIME,
NOTEHISTORY.COMMITRECID
FROM REQCOMMIT
INNER JOIN NOTEHISTORY ON REQCOMMIT.RECID = NOTEHISTORY.COMMITRECID
INNER JOIN (SELECT COMMITRECID, MIN(MODIFIEDDATETIME) DT FROM NOTEHISTORY GROUP BY COMMITRECID) a on a.COMMITRECID = NOTEHISTORY.COMMITRECID and a.DT = NOTEHISTORY.MODIFIEDDATETIME
WHERE REQCOMMIT.PORECID = 1234
Please find below image for make understanding my issues. I have a table as shown below picture. I need to get only highlighted (yellow) records. What is the best method to find these records?
In SQL Server 2012+, you can use the lead() and lag() functions. However, this is not available in SQL Server 2008. Here is a method using outer apply:
select t.*
from t outer apply
(select top 1 tprev.*
from t tprev
on tprev.time < t.time
order by tprev.time desc
) tprev outer apply
(select top 1 tnext.*
from t tnext
on tnext.time > t.time
order by tnext.time asc
)
where (t.cardtype = 1 and tnext.cardtype = 2) or
(t.cardtype = 2 and tprev.cardtype = 1);
With your sample data, it would also be possible to use self joins on the id column. This seems unsafe, though, because there could be gaps in that columns values.
Havent tried this, but I think it should work. First, make a view of the table in your question, with the rownumber included as one column:
CREATE VIEW v AS
SELECT
ROW_NUMBER() OVER(ORDER BY id) AS rownum,
id,
time,
card,
card_type
FROM table
Then, you can get all the rows of type 1 followed by a row of type 2 like this:
SELECT
a.id,
-- And so on...
FROM v AS a
JOIN v AS b ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
And all the rows of type 2 preceded by a row of type 1 like this:
SELECT
b.id,
-- And so on...
FROM v AS b
JOIN v AS a ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
To get them both in the same set of results, you can just use UNION ALL. Technically, you don't need the view. You could use nested selects instead, but since you will need to query the table four times it might be nice to have it as a view.
Also, if the ID is continous (it goes 1, 2, 3 without any gaps), you don't need the rownum and can just use the ID instead.
here is a code you can run in sql server
select * from Table_name where id in (1,2,6,7,195,160,164,165)
The top query is just showing the results I am expecting before I join another table to perform some calculations in Crystal Reports.
select
DriveID, FromDateTime, accountid, LocationID, StatusID
from
DriveMaster
where
AccountID = '3813'
order by
FromDateTime desc;
Results:
Query Results
This second query is where I apply a couple of filters (specifying accountid, locationid, statusid, and which occur before a specific date).
select
dm.driveid, dm.fromdatetime, dm.accountid, dpact.ProcedureProjection,
dpact.ProceduresPerformed, dpact.ProductProjection, dpact.ProductsCollected,
dm.locationid
from
rpt_drivemaster dm
inner join
driveprojectionandcollectedtotals dpact on dm.driveid = dpact.driveid
where
dm.statusid = 2
and dm.accountid = '3813'
and dm.locationid = '4018'
and dm.fromdatetime < '20140602'
and dm.fromdatetime in (select top 3 dm2.fromdatetime
from rpt_drivemaster dm2
where dm2.accountid = '3813'
and dm2.statusid = 2
order by dm2.fromdatetime desc);
The only results I am getting however are:
Query Results 2
Based on the earlier query, I was expecting results for DriveIDs of:
1. 314933
2. 205250
3. 184779
Any suggestions on what I am missing here?
The problem is in your subquery that is passed in the IN – it is returning three rows with DriverID 548002,314933 and 205250. The first row has LocationID = 31036 so it doesn't go in the result set because in your main query there is a condition dm.locationid='4018'.You should pass this condition in the subquery too, to get the desired result :
select top 3 dm2.fromdatetime
from rpt_drivemaster dm2
where dm2.accountid='3813'
and dm2.statusid=2
and dm2.LocationID = '4018'
order by dm2.fromdatetime desc
I have a table "defects" in the following format:
id status stat_date line div area
1 Open 09/21/09 F A cube
1 closed 01/01/10 F A cube
2 Open 10/23/09 B C Back
3 Open 11/08/09 S B Front
3 closed 12/12/09 S B Front
My problem is that I want to write a query that just extracts the "Open" defects. If I write a query to simply extract all open defects, then I get the wrong result because there are some defects,
that have 2 records associated with it. For example, with the query that I wrote I would get defect id#s 1 and 3 in my result even though they are closed. I hope I have explained my problem well. Thank you.
Use:
SELECT t.*
FROM DEFECTS t
JOIN (SELECT d.id,
MAX(d.stat_date) 'msd'
FROM DEFECTS d
GROUP BY d.id) x ON x.id = t.id
AND x.msd = t.stat_date
WHERE t.status != 'closed'
The join is getting the most recent date for each id value.
Join back to the original table on based on the id and date in order to get only the most recent rows.
Filter out those rows with the closed status to know the ones that are currently open
So you want to get the most recent row per id and of those, only select those that are open. This is a variation of the common greatest-n-per-group problem.
I would do it this way:
SELECT d1.*
FROM defects d1
LEFT OUTER JOIN defects d2
ON (d1.id = d2.id AND d1.stat_date < d2.stat_date)
WHERE d2.id IS NULL
AND d1.status = 'Open';
Select *
from defects d
where status = 'Open'
and not exists (
select 1 from defects d1
where d1.status = 'closed'
and d1.id = d.id
and d1.stat_date > d.stat_date
)
This should get what you want. I wouldn't have a record for open and closing a defect, rather just a single record to track a single defect. But that may not be something you can change easily.
SELECT id FROM defects
WHERE status = 'OPEN' AND id NOT IN
(SELECT id FROM defects WHERE status = 'closed')
This query handles multiple opens/closes/opens, and only does one pass through the data (i.e. no self-joins):
SELECT * FROM
(SELECT DISTINCT
id
,FIRST_VALUE(status)
OVER (PARTITION BY id
ORDER BY stat_date desc)
as last_status
,FIRST_VALUE(stat_date)
over (PARTITION BY id
ORDER BY stat_date desc)
AS last_stat_date
,line
,div
,area
FROM defects)
WHERE last_status = 'Open';
SpousesTable
SpouseID
SpousePreviousAddressesTable
PreviousAddressID, SpouseID, FromDate, AddressTypeID
What I have now is updating the most recent for the whole table and assigning the most recent regardless of SpouseID the AddressTypeID = 1
I want to assign the most recent SpousePreviousAddress.AddressTypeID = 1
for each unique SpouseID in the SpousePreviousAddresses table.
UPDATE spa
SET spa.AddressTypeID = 1
FROM SpousePreviousAddresses AS spa INNER JOIN Spouses ON spa.SpouseID = Spouses.SpouseID,
(SELECT TOP 1 SpousePreviousAddresses.* FROM SpousePreviousAddresses
INNER JOIN Spouses AS s ON SpousePreviousAddresses.SpouseID = s.SpouseID
WHERE SpousePreviousAddresses.CountryID = 181 ORDER BY SpousePreviousAddresses.FromDate DESC) as us
WHERE spa.PreviousAddressID = us.PreviousAddressID
I think I need a group by but my sql isn't all that hot. Thanks.
Update that is Working
I was wrong about having found a solution to this earlier. Below is the solution I am going with
WITH result AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY SpouseID ORDER BY FromDate DESC) AS rowNumber, *
FROM SpousePreviousAddresses
WHERE CountryID = 181
)
UPDATE result
SET AddressTypeID = 1
FROM result WHERE rowNumber = 1
Presuming you are using SQLServer 2005 (based on the error message you got from the previous attempt) probably the most straightforward way to do this would be to use the ROW_NUMBER() Function couple with a Common Table Expression, I think this might do what you are looking for:
WITH result AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY SpouseID ORDER BY FromDate DESC) as rowNumber,
*
FROM
SpousePreviousAddresses
)
UPDATE SpousePreviousAddresses
SET
AddressTypeID = 2
FROM
SpousePreviousAddresses spa
INNER JOIN result r ON spa.SpouseId = r.SpouseId
WHERE r.rowNumber = 1
AND spa.PreviousAddressID = r.PreviousAddressID
AND spa.CountryID = 181
In SQLServer2005 the ROW_NUMBER() function is one of the most powerful around. It is very usefull in lots of situations. The time spent learning about it will be re-paid many times over.
The CTE is used to simplyfy the code abit, as it removes the need for a temporary table of some kind to store the itermediate result.
The resulting query should be fast and efficient. I know the select in the CTE uses *, which is a bit of overkill as we dont need all the columns, but it may help to show what is happening if anyone want to see what is happening inside the query.
Here's one way to do it:
UPDATE spa1
SET spa1.AddressTypeID = 1
FROM SpousePreviousAddresses AS spa1
LEFT OUTER JOIN SpousePreviousAddresses AS spa2
ON (spa1.SpouseID = spa2.SpouseID AND spa1.FromDate < spa2.FromDate)
WHERE spa1.CountryID = 181 AND spa2.SpouseID IS NULL;
In other words, update the row spa1 for which no other row spa2 exists with the same spouse and a greater (more recent) date.
There's exactly one row for each value of SpouseID that has the greatest date compared to all other rows (if any) with the same SpouseID.
There's no need to use a GROUP BY, because there's kind of an implicit grouping done by the join.
update: I think you misunderstand the purpose of the OUTER JOIN. If there is no row spa2 that matches all the join conditions, then all columns of spa2.* are returned as NULL. That's how outer joins work. So you can search for the cases where spa1 has no matching row spa2 by testing that spa2.SpouseID IS NULL.
UPDATE spa SET spa.AddressTypeID = 1
WHERE spa.SpouseID IN (
SELECT DISTINCT s1.SpouseID FROM Spa S1, SpousePreviousAddresses S2
WHERE s1.SpouseID = s2.SpouseID
AND s2.CountryID = 181
AND s1.PreviousAddressId = s2.PreviousAddressId
ORDER BY S2.FromDate DESC)
Just a guess.