Select all rows with max date for each ID - sql

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

Related

Self join taking time

I am having below query which selects SUM of AAD_00TO30 columns depending upon some conditions.
The query executes in 1 sec when I remove below condition, but it takes more than a min when same condition is included.
Can someone please suggest me any alternative to modify the query for better performance.
AND A.AAD_DATE >= (SELECT MAX(B.AAD_DATE)
FROM MST_AR_AS_ON_DATE B
WHERE MONTH(B.AAD_DATE) = MONTH(A.AAD_DATE) AND YEAR(B.AAD_DATE) = YEAR(A.AAD_DATE))
Query:
SELECT '00-30 #66ff66',SUM(A.AAD_00TO30) FROM MST_AR_AS_ON_DATE A
WHERE MONTH(A.AAD_DATE) = MONTH(DATEADD(MM,-1,GETDATE()))
AND YEAR(A.AAD_DATE) = YEAR(DATEADD(MM,-1,GETDATE()))
AND A.AAD_RESP_NOW = 4
AND A.AAD_DATE >= (SELECT MAX(B.AAD_DATE)
FROM MST_AR_AS_ON_DATE B
WHERE MONTH(B.AAD_DATE) = MONTH(A.AAD_DATE) AND YEAR(B.AAD_DATE) = YEAR(A.AAD_DATE))
Try using RANK() to tag rows that meet the criteria of having the last date of the month. Then eliminate rows without a winning rank:
WITH
MST_AR_AS_ON_DATE_RANKED AS (
SELECT
*,
RANK() OVER (
PARTITION BY
YEAR(AAD_DATE),
MONTH(AAD_DATE)
ORDER BY
AAD_DATE DESC -- last day of month ranked highest
) AS AAD_DATE_RANK
FROM
MST_AR_AS_ON_DATE
)
SELECT
'00-30 #66ff66',
SUM(AAD_00TO30)
FROM
MST_AR_AS_ON_DATE_RANKED
WHERE
MONTH(AAD_DATE) = MONTH(DATEADD(MM,-1,GETDATE()))
AND YEAR(AAD_DATE) = YEAR(DATEADD(MM,-1,GETDATE()))
AND AAD_RESP_NOW = 4
AND AAD_DATE_RANK = 1
;

Oracle: filter all rows before the ID

I have a big query that brings me a lot of rows, and based on each row I use this another query as a subselect.
This subselect brings me the following result rest on Oracle:
SELECT oc3.ID_ORGAO_INTELIGENCIA,
oc3.ord,
lag(oc3.ID_ORGAO_INTELIGENCIA, 1, NULL) OVER (
ORDER BY oc3.ord) ultimo
FROM
( SELECT DISTINCT oc2.*
FROM
( SELECT oc1.ID_ORGAO_INTELIGENCIA,
oc1.ID_ORGAO_INTELIGENCIA_PAI,
oc1.SG_ORGAO_INTELIGENCIA,
rownum AS ord
FROM TB_ORGAO_INTERNO oc1
WHERE oc1.DH_EXCLUSAO IS NULL START WITH oc1.ID_ORGAO_INTELIGENCIA =
-- this is a value that come from an outer select
-- If I put the value directly, like: S.ID_ORGAO_INTELIGENCIA, it does not work... I dont know why...
(SELECT sa.ID_ORGAO_INTELIGENCIA
FROM TB_SOLICITACAO sa
WHERE sa.ID_SOLICITACAO = 1077)-- s.ID_SOLICITACAO)
CONNECT BY
PRIOR oc1.ID_ORGAO_INTELIGENCIA_PAI = oc1.ID_ORGAO_INTELIGENCIA) oc2
INNER JOIN TB_PERMISSAO pe2_ ON pe2_.ID_ORGAO_INTELIGENCIA = oc2.ID_ORGAO_INTELIGENCIA
INNER JOIN TB_USUARIO u_ ON u_.ID_USUARIO = pe2_.ID_USUARIO
WHERE pe2_.ID_STATUS_PERMISSAO = 7
AND pe2_.ID_ATRIBUICAO IN :atribuicoes
ORDER BY oc2.ord) oc3
The result:
That important value from each row is the S.ID_SOLICITACAO, because based on that value that the subquery will be started.
I need to be able to filter the results by oc3.ID_ORGAO_INTELIGENCIA where it brings me all the rows before that number.
So, If I filter by 430, only the row with 311 will return.
If I filter by 329, it will bring me the: 311 and 430.
Is there a way to achieve this result?
One option might be to use your current query as a CTE, and then filter data it returns. Something like this:
with ycq as
-- your current query
(select ...
from ...
)
select *
from ycq a
where a.ord < (select b.ord
from ycq b
where b.id_orgao_inteligencia = :par_id_orgao_inteligencia
);

Pivot rows to columns

I need to create one master table to present in reporting services, but i have an issue on how to combine the data.
To be more specific, i have one table named "Reservaciones" which store information from residences that have been reserved in certain dates.
Now for example, I´m grouping the information by this fields:
R.ClaTrab AS WorkerId
R.ClaUbicacion AS UbicationID
R.ClaEstancia AS ResidenceID
R.FechaIni AS InitialDay
R.FechaFin AS LastDay
And the result is First result**
As you see in the picture we have two rows duplicated, the number four and number five to be exact.
So far this is my code
SELECT
R.ClaTrab AS WorkerId,
MAX(E.NomEstancia) AS ResidenceName,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay
FROM Reservaciones AS R
INNER JOIN Estancias AS E ON E.ClaEstancia = R.ClaEstancia
WHERE E.ClaUbicacionEst = 3
GROUP BY R.ClaTrab,R.ClaUbicacion, R.ClaEstancia, R.FechaIni, R.FechaFin
ORDER BY R.FechaIni
I Want the result to be like this desire result, but i dont know how to do it, i have tried PIVOT but i cant get the result i want it.
If u need more information please, ask me.
thank you very much.
SOLUTION:
What i did is use the ROW NUMBER() and OVER PARTITION BY to create a group of workers in the same residence, then PIVOT the result in new columns.
SNIPPET
SELECT * FROM(
SELECT
MAX(E.NomEstancia) AS ResidenceName,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
T.NomTrab AS Worker,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
ROW_NUMBER() OVER(PARTITION BY FechaIni,FechaFin, R.ClaUbicacion, R.ClaEstancia ORDER BY T.NomTrab) AS GUEST
FROM Reservaciones AS R
INNER JOIN Estancias AS E ON E.ClaEstancia = R.ClaEstancia
INNER JOIN Trabajadores AS T ON T.ClaTrab = R.ClaTrab
WHERE E.ClaUbicacionEst = 3
GROUP BY T.NomTrab, R.ClaUbicacion, R.ClaEstancia, R.FechaIni,R.FechaFin) AS ONE
PIVOT( MAX(Worker) FOR GUEST IN ([1],[2],[3])) AS pvt
In the new query I added a new join to obtain the name of the workers
Since there can only be 2 workers, you can use Min and Max.
with cte as(
SELECT
R.ClaTrab AS WorkerId,
MAX(E.NomEstancia) AS ResidenceName,
R.ClaUbicacion AS UbicationID,
R.ClaEstancia AS ResidenceID,
DATEDIFF(DAY, R.FechaIni, R.FechaFin) AS NumberDays,
R.FechaIni AS InitialDay,
R.FechaFin AS LastDay
FROM
Reservaciones AS R
INNER JOIN
Estancias AS E
ON E.ClaEstancia = R.ClaEstancia
WHERE
E.ClaUbicacionEst = 3
GROUP BY
R.ClaTrab,
R.ClaUbicacion,
R.ClaEstancia,
R.FechaIni,
R.FechaFin),
cte2 as(
select
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay
,Worker1 = max(WorkerId)
,Worker2 = min(WorkerId)
from
cte
group by
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay)
select
ResidenceName
,UbicationID
,ResidenceID
,NumberDays
,InitalDay
,LastDay
,Worker1
,Worker2 = case when Worker1 = Worker2 then NULL else Worker2 end
from
cte2
ONLINE DEMO WITH PARTIAL TEST DATA

Postgres: Making column in first row contain sum of same column in other rows

I'm a newbie in postgres and i have a troubling issue.
Suppose the output of my SQL query is
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:26.976258";300
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:27.173523";100
What i want is to sum up all the 4th column, and so that the first row will contain the sum of the 4th column
123456789;"2014-11-20 12:30:35.454875";500;400;"2014-11-16 16:16:26.976258";300
My query is
select l.phone_no, l.loan_time, l.cents_loaned/100, r.cents_deducted/100, r.event_time,
r.cents_balance/100
from tbl_table1 l
LEFT JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
where l.phone_no=123456789
order by r.event_time desc
Any help will be appreciated.
Maybe this helps. It will add a new row containing the sum of the 4th column.
WITH query AS (
SELECT l.phone_no, l.loan_time, l.cents_loaned/100 AS cents_loaned,
r.cents_deducted/100 AS cents_deducted, r.event_time,
r.cents_balance/100 AS cents_balance,
ROW_NUMBER() OVER (ORDER BY r.event_time DESC) rn,
SUM(cents_deducted/100) OVER () AS sum_cents_deducted
FROM tbl_table1 l
LEFT
JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
WHERE l.phone_no=123456789
)
SELECT phone_no, loan_time, cents_loaned, cents_deducted, event_time, cents_balance
FROM query
WHERE rn > 1
UNION
ALL
SELECT phone_no, loan_time, cents_loaned, sum_cents_deducted, event_time, cents_balance
FROM query
WHERE rn = 1
Use a window function over the whole set (OVER ()) as frame:
select l.phone_no, l.loan_time, l.cents_loaned/100
, sum(r.cents_deducted) OVER () / 100 AS total_cents_deducted
, r.event_time, r.cents_balance/100
FROM tbl_table1 l
LEFT JOIN tbl_table2 r ON l.tb1_id = r.tbl2_id
WHERE l.phone_no = 123456789
ORDER BY r.event_time desc
This will return all rows, not just the first. Your question is unclear as to that.

How to display row data in separate column in sql server 2012

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.