SQL select from a group - tsql
Suppose we have the following table data:
ID parent stage submitted
1 1 1 1
2 1 2 1
3 1 3 0
4 1 4 0
5 5 1 1
6 5 2 1
7 5 3 1
8 5 4 1
As you can see we have 2 groups (that have the same parent). I want to select the latter stage that is submitted. In the above example i want to select the ID`s 2 and 8. I am completely lost so if anyone can help it will be appreciated a lot. :)
SELECT T.ID, T.PARENT, T.STAGE
from
T,
(
select PARENT, MAX( STAGE) MAX_STAGE
from T
where SUBMITTED = 1
GROUP BY PARENT
) M
where
T.STAGE = M.MAX_STAGE
AND T.PARENT = M.PARENT
Explanation:
First, isolate the max stage for each group with submitted = 1 (the inner select).
Then, join the result with the real table, to filter out the records with no max stage.
Select Parent, max(Id)
From tbl t
Inner Join
(
Select Parent, max(Stage) as Stage
from tbl t
Where Submitted = 1
Group by Parent
) submitted
on t.Parent = submitted.parent and
t.stage = submitted.stage
Group by Parent
This should do it:
SELECT
T1.id,
T1.parent,
T1.stage,
T1.submitted
FROM
Some_Table T1
LEFT OUTER JOIN Some_Table T2 ON
T2.parent = T1.parent AND
T2.submitted = 1 AND
T2.stage > T1.stage
WHERE
T1.submitted = 1 AND
T2.id IS NULL
SELECT * FROM Table WHERE ID = 2 OR ID = 8
Is this what you want?
Related
Postgresql group by relation
I want to group the records by relation. products table: id price 1 100 2 200 3 300 4 400 product_properties table: id productId propertyId 1 1 2 2 1 3 3 2 2 4 2 3 5 3 4 6 4 4 The query should select lowest price group by product_properties. I mean, If products have same properties in product_properties, query should return product that has lowest price. So, For these tables query should return products that have ids 1,3. I use TypeORM, I tried join the relation and distinct on relation alias name but its not worked. How can I achieve this?
I wrote two variants query for you: -- variant 1 select distinct t1.product_id from ( select pr.price, pp.product_id, pp.property_id, min(pr.price) OVER(PARTITION BY pp.property_id) as min_price from test.product_properties pp inner join test.products pr on pp.product_id = pr.id ) t1 where t1.price = t1.min_price; -- variant 2 select distinct t1.product_id from test.product_properties t1 inner join test.products t2 on t1.product_id = t2.id inner join ( select pp.property_id, min(pr.price) as min_price from test.product_properties pp inner join test.products pr on pp.product_id = pr.id group by pp.property_id ) t3 on t3.property_id = t1.property_id and t3.min_price = t2.price;
Capture First Character of Last Group of 1s in a Binary Series Part II: Multiple IDs
I have data something like this: ID 1 1 1 1 1 1 1 1 1 1 1 1 Month J F M A M J J A S O N D Status 1 0 0 1 0 1 0 0 1 1 1 1 ID 2 2 2 2 2 2 2 2 2 2 2 2 Month J F M A M J J A S O N D Status 1 0 1 0 1 0 1 0 1 0 1 1 ID 3 3 3 3 3 3 3 3 3 3 3 3 Month J F M A M J J A S O N D Status 0 0 0 0 0 0 0 0 0 0 0 1 Using t-SQL, I am trying to capture the month corresponding to the first STATUS = 1 in the last group of 1s for each ID, i.e., September, November and December in this example. Here is the code I'm using: IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL DROP TABLE #Temp1 ;WITH PARTITIONED1 AS (SELECT t0.ID , t0.Year_Month , LAST_VALUE(t0.Year_Month) OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS STATUS , ROW_NUMBER() OVER (PARTITION BY t0.Account_Number ORDER BY t0.Year_Month) AS rn1 FROM #Temp0 t0 ) SELECT * INTO #Temp1 FROM PARTITIONED1 p1 ORDER BY t0.ID , t0.Year_Month IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp SELECT * INTO #Temp FROM #Temp1 t1 WHERE t1.rn1 = (SELECT MAX(b.rn1) + 1 FROM #Temp1 b WHERE b.STATUS = 0) GROUP BY t1.ID , t1.Year_Month , t1.rn1 However, this just returns the last instance where STATUS = 1 is achieved overall as the first 1 of the last group of 1s, in this case January. I've tried using CASE statements and grouping in various combinations (hence the intermediate step reading the data into #Temp1), but have not been able to get results for all three IDs; is anyone able to assist? Thanks in advance!
Assuming Ju for June and Jl for July: --Sample Data IF OBJECT_ID('tempdb..#Temp0') IS NOT NULL DROP TABLE #Temp0 CREATE TABLE #Temp0 (ID INT, Year_Month VARCHAR(1), Status INT) INSERT INTO #Temp0 VALUES(1,'J',1),(1,'F',0),(1,'M',0),(1,'A',1),(1,'M',0),(1,'J',1),(1,'J',0),(1,'A',0),(1,'S',1),(1,'O',1),(1,'N',1),(1,'D',1),(2,'J',1),(2,'F',0),(2,'M',1),(2,'A',0),(2,'M',1),(2,'J',0),(2,'J',1),(2,'A',0),(2,'S',1),(2,'O',0),(2,'N',1),(2,'D',1),(3,'J',0),(3,'F',0),(3,'M',0),(3,'A',0),(3,'M',0),(3,'J',0),(3,'J',0),(3,'A',0),(3,'S',0),(3,'O',0),(3,'N',0),(3,'D',1); --Query WITH A AS ( SELECT *, CASE Year_Month WHEN 'J' THEN 1 WHEN 'F' THEN 2 WHEN 'M' THEN 3 WHEN 'A' THEN 4 WHEN 'M' THEN 5 WHEN 'Ju' THEN 6 WHEN 'Jl' THEN 7 WHEN 'A' THEN 8 WHEN 'S' THEN 9 WHEN 'O' THEN 10 WHEN 'N' THEN 11 WHEN 'D' THEN 12 END AS MonthNumber FROM #Temp0 ), StartingPoints AS ( SELECT ID, Year_Month, MonthNumber, Status FROM A WHERE NOT EXISTS ( SELECT 1 FROM A AS B WHERE B.ID=A.ID AND B.Status=A.Status-1 ) ), MonthRanking AS ( SELECT A.*, ROW_NUMBER( ) OVER( PARTITION BY A.ID ORDER BY A.MonthNumber ) AS rownum FROM A INNER JOIN ( SELECT ID, MAX( MonthNumber )+1 AS StartOfLastGroup FROM StartingPoints GROUP BY ID ) AS B ON A.ID=B.ID AND A.MonthNumber>=B.StartOfLastGroup ) SELECT * FROM MonthRanking WHERE rownum=1; Results: If Month Names are recorded in Full as in July, June then this would work as well: WITH StartingPoints AS (SELECT ID, Year_Month, MonthNUmber = MONTH('01-'+Year_Month+'-2010'), Status FROM #Temp0 WHERE NOT EXISTS ( SELECT 1 FROM #Temp0 AS B WHERE B.ID = #Temp0.ID AND B.Status = #Temp0.Status - 1 )), MonthRanking AS (SELECT A.*, ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY MONTH('01-'+A.Year_Month+'-2010')) AS rownum FROM #Temp0 AS A INNER JOIN ( SELECT ID, MAX(MonthNumber) + 1 AS StartOfLastGroup FROM StartingPoints GROUP BY ID ) AS B ON A.ID = B.ID AND MONTH('01-'+A.Year_Month+'-2010') >= B.StartOfLastGroup) SELECT * FROM MonthRanking WHERE rownum = 1; Results: And if we assume that the data is as Iamdave assumes then it simply like so: WITH StartingPoints AS (SELECT ID, Year_Month, Status FROM #Temp0 WHERE NOT EXISTS ( SELECT 1 FROM #Temp0 AS B WHERE B.ID = #Temp0.ID AND B.Status = #Temp0.Status - 1 )), MonthRanking AS (SELECT A.*, ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY Year_Month) AS rownum FROM #Temp0 AS A INNER JOIN ( SELECT ID, MAX(Year_Month) + 1 AS StartOfLastGroup FROM StartingPoints GROUP BY ID ) AS B ON A.ID = B.ID AND A.Year_Month >= B.StartOfLastGroup) SELECT * FROM MonthRanking WHERE rownum = 1; Results:
You can do this with a couple derived tables that stack two window functions on top of one another (which can't be done in the same select). I have assumed that your data is slightly different to the table you have provided, based on the column names in your query. If they are not as I have them below, I strongly recommend having a look at how you store your data: declare #t table(ID int, YearMonth int,StatusValue bit); insert into #t values (1,201501,1),(1,201502,0),(1,201503,0),(1,201504,1),(1,201505,0),(1,201506,1),(1,201507,0),(1,201508,0),(1,201509,1),(1,201510,1),(1,201511,1),(1,201512,1),(2,201601,1),(2,201602,0),(2,201603,1),(2,201604,0),(2,201605,1),(2,201606,0),(2,201607,1),(2,201608,0),(2,201609,1),(2,201610,0),(2,201611,1),(2,201612,1),(3,201701,0),(3,201702,0),(3,201703,0),(3,201704,0),(3,201705,0),(3,201706,0),(3,201707,0),(3,201708,0),(3,201709,0),(3,201710,0),(3,201711,0),(3,201712,1); with c as ( select ID ,YearMonth ,StatusValue ,case when StatusValue = 1 and lead(StatusValue,1,1) over (partition by ID order by YearMonth desc) = 0 then 1 else 0 end as c from #t ), sc as ( select ID ,YearMonth ,StatusValue ,sum(c) over (partition by ID order by YearMonth desc) as sc from c where c = 1 ) select ID ,YearMonth ,StatusValue from sc where sc = 1 order by ID; Output: +----+-----------+-------------+ | ID | YearMonth | StatusValue | +----+-----------+-------------+ | 1 | 201509 | 1 | | 2 | 201611 | 1 | | 3 | 201712 | 1 | +----+-----------+-------------+
Subsetting records that contain multiple values in one column
In my postgres table, I have two columns of interest: id and name - my goal is to only keep records where id has more than one value in name. In other words, would like to keep all records of ids that have multiple values and where at least one of those values is B UPDATE: I have tried adding WHERE EXISTS to the queries below but this does not work The sample data would look like this: > test id name 1 1 A 2 2 A 3 3 A 4 4 A 5 5 A 6 6 A 7 7 A 8 2 B 9 1 B 10 2 B and the output would look like this: > output id name 1 1 A 2 2 A 8 2 B 9 1 B 10 2 B How would one write a query to select only these kinds records?
Based on your description you would seem to want: select id, name from (select t.*, min(name) over (partition by id) as min_name, max(name) over (partition by id) as max_name from t ) t where min_name < max_name;
This can be done using EXISTS: select id, name from test t1 where exists (select * from test t2 where t1.id = t2.id and t1.name <> t2.name) -- this will select those with multiple names for the id and exists (select * from test t3 where t1.id = t3.id and t3.name = 'B') -- this will select those with at least one b for that id
Those records where for their id more than one name shines up, right? This could be formulated in "SQL" as follows: select * from table t1 where id in ( select id from table t2 group by id having count(name) > 1)
Remove duplicate with separate column check TSQL
I have 2 tables having same columns and permission records in it. One columns named IsAllow is available in both tables. I am getting records of both tables in combine using UNION But want to skip similar records if IsAllow = 0 in any one column - I don't want those records. But UNION returns all records and am getting confused. Below are columns IsAllow, UserId, FunctionActionId I tried union but it gives both records. I want to exclude IsAllow = 0 in either table. Sample data table 1 IsAllow UserId FunctionActionId 1 2 5 1 2 8 Sample data table 2 IsAllow UserId FunctionActionId 0 2 5 (should be excluded) 1 2 15
You can try this: ;with cte as(select *, row_number() over(partition by UserId, FunctionActionId order by IsAllow desc) rn from (select * from table1 union all select * from table2) t) select * from cte where rn = 1 and IsAllow = 1 Version2: select distinct coalesce(t1.UserId, t2.UserId) as UserId, coalesce(t1.FunctionActionId, t2.FunctionActionId) as FunctionActionId, 1 as IsAllow from tabl1 t1 full join table2 t2 on t1.UserId = t2.UserId and t1.FunctionActionId = t2.FunctionActionId where (t1.IsAllow = 1 and t2.IsAllow = 1) or (t1.IsAllow = 1 and t2.IsAllow is null) or (t1.IsAllow is null and t2.IsAllow = 1)
How to sum items from subtable in SQL
Let's say I have table orders id name 1 order1 2 order2 3 order3 and subtable items id parent amount price 1 1 1 10 2 1 3 20 3 2 2 5 4 2 5 1 I would like to create query with order with added column value. it should calculate order with all relevant items id name value 1 order1 70 2 order2 15 3 order3 0 Is this possible with TSQL
GROUP BY and SUM would do it, need to use left join and isnull as you don't have items for all orders. SELECT o.id, o.name, isnull(sum(i.amount*i.price),0) as value FROM orders o left join items i on o.id = i.parent group by o.id, o.name
I think you're looking for something like this SELECT o.name, i.Value FROM orders o WITH (NOLOCK) LEFT JOIN (SELECT parent, SUM(price) AS Value FROM items WITH (NOLOCK) GROUP BY parent) i ON o.id = i.parent ...seems like RADAR beat me to the answer. EDIT: missing the ON line.