Subtracting current from previous row by date and ID - sql

I'd like to extend this answer here by including an ID as a grouping column. I tried including a 'group by' clause without success.
+----------+--------------+----------
|NAV_Date |NetAssetValue | ID |
+----------+--------------+---------+
|12/31/2012| $4,000| A |
+----------+--------------+---------+
|03/31/2013| $5,000| A |
+----------+--------------+---------+
|12/31/2012| $4,000| B |
+----------+--------------+---------+
|03/31/2013| $5,000| B |
+----------+--------------+---------+
select NAV_date, NAV_value, (NAV_value / prev_value) - 1
from (select t.*,
(select top 1 NAV_value
from YOURTABLENAMEGOESHERE as t2
where t2.NAV_date < t.NAV_date
group by Nav_ID, Nav_value
order by t2.NAV_date desc
) as prev_value
from YOURTABLENAMEGOESHERE as t
) as t

Try this:
select
NAV_date,
NAV_value,
(NAV_value /
(select top 1 NAV_value
from YOURTABLENAMEGOESHERE as t2
where t2.NAV_date < t.NAV_date
order by t2.NAV_date desc) - 1
from
YOURTABLENAMEGOESHERE as t

Related

SQL sum based on two group by

I had one table
ID | khk | ts
11AH | 10 | 2
11AH | 10 | 2
11AH | 9 | 1
22AH | 5 | 2
22AH | 5 | 3
and I need sum(ts) for grouped ID (but only if count id is more than 2) and from this only if grouped khk count is more than 1)
So for id 11AH is sum(ts) = 4 (not 5) and for 22AH nothing, because they are only two.
I try something like this, but its not right
select sum(ts),id from table group by id,khk having count(id)>2 and count(khk)>1;
Try below
DEMO
select * from
(select id,khk, sum(ts) as ts,(select count(id) from cte1 b where a.id=b.id) as cnt
from cte1 a
group by id,khk
having count(*)>1)X where cnt>2
OUTPUT:
id khk ts cnt
11AH 10 4 3
you can try by using window function
with cte
(
select id,khk,ts, count(*) over(partition by id order by id) as id_cnt,
count(*) over(partition by khk order by khk) as khk_cnt
) select id,khk,sum(ts)
where id_cnt>2 and khk_cnt>1
group by id,khk
I recommend using analytic functions rather than subqueries:
select id, khk, sum_ts
from (select t.id, t.khk, sum(ts) as sum_ts,
count(*) as cnt_id_khk,
count(*) over (partition by t.id) as cnt_id
from t
group by id, khk
) t
where cnt_id_khk > 1 and cnt_id > 1

Get row which matched in each group

I am trying to make a sql query. I got some results from 2 tables below. Below results are good for me. Now I want those values which is present in each group. for example, A and B is present in each group(in each ID). so i want only A and B in result. and also i want make my query dynamic. Could anyone help?
| ID | Value |
|----|-------|
| 1 | A |
| 1 | B |
| 1 | C |
| 1 | D |
| 2 | A |
| 2 | B |
| 2 | C |
| 3 | A |
| 3 | B |
In the following query, I have placed your current query into a CTE for further use. We can try selecting those values for which every ID in your current result appears. This would imply that such values are associated with every ID.
WITH cte AS (
-- your current query
)
SELECT Value
FROM cte
GROUP BY Value
HAVING COUNT(DISTINCT ID) = (SELECT COUNT(DISTINCT ID) FROM cte);
Demo
The solution is simple - you can do this in two ways at least. Group by letters (Value), aggregate IDs with SUM or COUNT (distinct values in ID). Having that, choose those letters that have the value for SUM(ID) or COUNT(ID).
select Value from MyTable group by Value
having SUM(ID) = (SELECT SUM(DISTINCT ID) from MyTable)
select Value from MyTable group by Value
having COUNT(ID) = (SELECT COUNT(DISTINCT ID) from MyTable)
Use This
WITH CTE
AS
(
SELECT
Value,
Cnt = COUNT(DISTINCT ID)
FROM T1
GROUP BY Value
)
SELECT
Value
FROM CTE
WHERE Cnt = (SELECT COUNT(DISTINCT ID) FROM T1)

SQL ORACLE - get min row with sequence equal values

My have table similar to:
MY_DAT | STATUS
=========|========
1.1.2017 | A
2.1.2017 | A
3.1.2017 | A
4.1.2017 | B
5.1.2017 | B
6.1.2017 | A
7.1.2017 | C
8.1.2017 | A
9.1.2017 | A
10.1.2017| A
I want SQL query that by date(MY_DAT) return min date with equal STATUS without interruption.
Example
MY_DAT = '1.1.2017' -> '1.1.2017',A
MY_DAT = '3.1.2017' -> '1.1.2017',A
MY_DAT = '10.1.2017' -> '8.1.2017',A
MY_DAT = '5.1.2017' -> '4.1.2017',B
I don't how this sql have to look like.
EDIT
I need result to be for every date. In this example result have to be:
MY_DAT | STATUS | BEGIN
=========|========|========
1.1.2017 | A |1.1.2017
2.1.2017 | A |1.1.2017
3.1.2017 | A |1.1.2017
4.1.2017 | B |4.1.2017
5.1.2017 | B |4.1.2017
6.1.2017 | A |6.1.2017
7.1.2017 | C |7.1.2017
8.1.2017 | A |8.1.2017
9.1.2017 | A |8.1.2017
10.1.2017| A |8.1.2017
ANSWER
select my_date, status,
min(my_date) over (partition by grp, status) as begin
from (select my_date,status ,
row_number() over(order by my_date)
-row_number() over(partition by status order by my_date) as grp
from tbl ) t
Thanks to Vamsi Prabhala
Use a difference of row numbers approach to assign groups to consecutive rows with same status. (Run the inner query to see this.). After this, it is just a group by operation to get the min date.
select status,min(my_date)
from (select my_date,status
,row_number() over(order by my_date)
-row_number() over(partition by status order by my_date) as grp
from tbl
) t
group by grp,status
Please try this.
SELECT status, min(my_dat)
FROM dates
GROUP BY status
OK, then what about this?
SELECT *
FROM dates
INNER JOIN
(
SELECT status, min(my_dat)
FROM dates
GROUP BY status
) sub
ON dates.status = sub.status

Selecting Top 1 for Every ID

I have the following table:
| ID | ExecOrd | date |
| 1 | 1.0 | 3/4/2014|
| 1 | 2.0 | 7/7/2014|
| 1 | 3.0 | 8/8/2014|
| 2 | 1.0 | 8/4/2013|
| 2 | 2.0 |12/2/2013|
| 2 | 3.0 | 1/3/2014|
| 2 | 4.0 | |
I need to get the date of the top ExecOrd per ID of about 8000 records, and so far I can only do it for one ID:
SELECT TOP 1 date
FROM TABLE
WHERE DATE IS NOT NULL and ID = '1'
ORDER BY ExecOrd DESC
A little help would be appreciated. I have been trying to find a similar question to mine with no success.
There are several ways of doing this. A generic approach is to join the table back to itself using max():
select t.date
from yourtable t
join (select max(execord) execord, id
from yourtable
group by id
) t2 on t.id = t2.id and t.execord = t2.execord
If you're using 2005+, I prefer to use row_number():
select date
from (
select row_number() over (partition by id order by execord desc) rn, date
from yourtable
) t
where rn = 1;
SQL Fiddle Demo
Note: they will give different results if ties exist.
;with cte as (
SELECT id,row_number() over(partition by ID order byExecOrd DESC) r
FROM TABLE WHERE DATE IS NOT NULL )
select id from
cte where r=1

MSSQL: Only last entry in GROUP BY (with id)

Following / copying computhomas's question, but adding some twists...
I have the following table in MSSQL2008
id | business_key | result | date
1 | 1 | 0 | 9
2 | 1 | 1 | 8
3 | 2 | 1 | 7
4 | 3 | n | 6
5 | 4 | 1 | 5
6 | 4 | 0 | 4
And now i want to group based on the business_key returning the complete entry with the newest date.
So my expected result is:
id | business_key | result | date
1 | 1 | 0 | 9
3 | 2 | 1 | 7
4 | 3 | n | 6
5 | 4 | 1 | 5
I also bet that there is a way to achieve that, i just can't find / see / think of it at the moment.
edit: sorry about this, I actually meant something else from original question I did. I felt like editing this might be better than accepting a solution and making another question. my original problem was that I am not filtering by id.
SELECT t.*
FROM
(
SELECT *, ROW_NUMBER() OVER
(
PARTITION BY [business_key]
ORDER BY [date] DESC
) AS [RowNum]
FROM yourTable
) AS t
WHERE t.[RowNum] = 1
SELECT
*
FROM
mytable
WHERE
ID IN (SELECT MAX(ID) FROM mytable GROUP BY business_key)
SELECT
MAX(T1.id) AS [id],
T1.business_key,
T1.result
FROM
dbo.My_Table T1
LEFT OUTER JOIN dbo.My_Table T2 ON
T2.business_key = T1.business_key AND
T2.id > T1.id
WHERE
T2.id IS NULL
GROUP BY T1.business_key,
T1.result
ORDER BY MAX(T1.id)
Edited based on clarifications
SELECT M1.*
FROM My_Table M1
INNER JOIN
(
SELECT [business_key], MAX([date]) as MaxDate
FROM My_Table
GROUP BY [business_key]
) M2 ON M1.business_key = M2.business_key AND M1.[date] = M2.MaxDate
ORDER BY M1.[id]
Assuming the combination of business_key & date is unique then....
Working example (3rd time is a charm):
declare #src as table(id int, business_key int,result int,[date] int)
insert into #src
SELECT 1,1,0,9
UNION SELECT 2,1,1,8
UNION SELECT 3,2,1,7
UNION SELECT 4,3,1,6
UNION SELECT 5,4,1,5
UNION SELECT 6,4,0,4
;with bkdate(business_key,[date])
AS
(
select business_key,MAX([date])
from #src
group by business_key
)
select src.* from #src src
inner join bkdate
ON src.[date] = bkdate.date
and src.business_key = bkdate.business_key
order by id
How about (edited after question change):
with latestdate as (
select business_key, maxdate=max(date)
from the_table
group by business_key
), latest as (
select ID = max(id)
from the_table
inner join latestdate
on the_table.business_key=latestdate.business_key
and the_table.date=latestdate.maxdate
group by the_table.business_key
)
select the_table.*
from the_table
inner join latest
on latest.id=the_table.id