I've tried to search for something related and similar, but, couldn't find it.
This is a table that I need to get as result:
+-----+-----------+------+-------------------+
| ID | PARENT_ID | CODE | NAME |
+-----+-----------+------+-------------------+
| 218 | NULL | 1445 | First One |
| 235 | 218 | 2 | First Child |
| 247 | 235 | 45 | First Grandchild |
| 246 | 235 | 55 | Second Grandchild |
| 230 | 218 | 3 | Second Child |
| 238 | 230 | 12 | Third Grandchild |
| 231 | 230 | 20 | Fourth Grandchild |
+-----+-----------+------+-------------------+
The order must be by it's hierarchy followed by it's code.
I need this to make an assertion. And, if it's possible, I would like to get this only doing a query, without a method to sort this list.
This is a sample of what I'm trying to assert:
Tree Hierarchy
What I've done so far, it's the following recursive query:
WITH CTE (ID, PARENT_ID, CODE, NAME)
AS
-- Anchor:
(SELECT
ID,
PARENT_ID,
CODE,
NAME
FROM WAREHOUSE
WHERE PARENT_ID IS NULL
UNION ALL
-- Level:
SELECT
W.ID,
W.PARENT_ID,
W.CODE,
W.NAME
FROM WAREHOUSE AS W
INNER JOIN CTE
ON R.PARENT_ID = CTE.ID)
SELECT *
FROM CTE
I appreciate any help on this!
Thanks in advance!
Looks like you can use the [CODE] sequence in a hierarchyid path
Example
Declare #YourTable Table ([ID] int,[PARENT_ID] int,[CODE] varchar(50),[NAME] varchar(50))
Insert Into #YourTable Values
(218,NULL,1445,'First One')
,(235,218,2,'First Child')
,(247,235,45,'First Grandchild')
,(246,235,55,'Second Grandchild')
,(230,218,3,'Second Child')
,(238,230,12,'Third Grandchild')
,(231,230,20,'Fourth Grandchild')
;with cteP as (
Select ID
,PARENT_ID
,[Code]
,Name
,HierID = convert(hierarchyid,concat('/',[Code],'/'))
From #YourTable
Where Parent_ID is null
Union All
Select ID = r.ID
,PARENT_ID = r.PARENT_ID
,r.[Code]
,Name = r.Name
,HierID = convert(hierarchyid,concat(p.HierID.ToString(),r.[Code],'/'))
From #YourTable r
Join cteP p on r.PARENT_ID = p.ID)
Select Lvl = HierID.GetLevel()
,ID
,PARENT_ID
,[Code]
,Name
From cteP A
Order By A.HierID
Returns
Lvl ID PARENT_ID Code Name
1 218 NULL 1445 First One
2 235 218 2 First Child
3 247 235 45 First Grandchild
3 246 235 55 Second Grandchild
2 230 218 3 Second Child
3 238 230 12 Third Grandchild
3 231 230 20 Fourth Grandchild
Related
I have table like:
name | timeStamp | previousValue | newValue
--------+---------------+-------------------+------------
Mark | 13.12.2020 | 123 | 155
Mark | 12.12.2020 | 123 | 12
Tom | 14.12.2020 | 123 | 534
Mark | 12.12.2020 | 123 | 31
Tom | 11.12.2020 | 123 | 84
Mark | 19.12.2020 | 123 | 33
Mark | 17.12.2020 | 123 | 96
John | 22.12.2020 | 123 | 69
John | 19.12.2020 | 123 | 33
I'd like to mix last_value, count (*) and group to get this result:
name | count | lastValue
--------+-----------+-------------
Mark | 5 | 33
Tom | 2 | 534
John | 2 | 69
This part:
select name, count(*)
from table
group by name
returns table:
name | count
--------+---------
Mark | 5
Tom | 2
John | 2
but I have to add the last value for each name.
How to do it?
Best regards!
LAST_VALUE is a windowed function, so you'll need to get that value first, and then aggregate:
WITH CTE AS(
SELECT [name],
[timeStamp], --This is a poor choice for a column's name. timestamp is a (deprecated) synonym of rowversion, and a rowversion is not a date and time value
previousValue,
newValue,
LAST_VALUE(newValue) OVER (PARTITION BY [name] ORDER BY [timeStamp] ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lastValue
FROM dbo.YourTable)
SELECT [Name],
COUNT(*) AS [count],
lastValue
FROM CTE
GROUP BY [Name],
lastValue;
I got a solution that works, but here's another one:
SELECT
[name], COUNT([name]), [lastValue]
FROM (
SELECT
[name], FIRST_VALUE([newValue]) OVER (PARTITION BY [name] ORDER BY TimeStamp DESC ROWS UNBOUNDED PRECEDING) AS [lastValue]
FROM [table]
) xyz GROUP BY [name], [lastValue]
Keep well!
I have below data set
Create table #table(
Message varchar(10),
ID varchar(5),
ParentID varchar(5))
Insert into #table
select 'Parent','123',''
UNION
select 'Child','234','123'
UNION
select 'Child','345','123'
UNION
select 'Child','145','123'
UNION
select 'Parent','333',''
UNION
select 'Child','567','333'
UNION
select 'Child','789','333'
UNION
select 'Child','100','333'
UNION
select 'Child','111','333'
select * from #table
when I select the data , data looks random. but i would like to have in below sequence
Message ID ParentID
Parent 123
Child 234 123
Child 345 123
Child 145 123
Parent 333
Child 567 333
Child 789 333
Child 100 333
Child 111 333
I tried with row number , it is not working somehow for the below sequence.
Can someone please help me ?
Use a CASE statement in ORDER BY, The following query should do what you want:
select * from #table
order by case when Message = 'Parent' then ID else ParentID end, ParentID
use this:
select message,id,parentid
from #table
order by case when parentid = '' then convert(int,id)-1 else parentid end
this solution is not based of message column and will correct with all data sets.
Use conditional sorting:
select * from #table
order by case when parentid = '' then id else parentid end, parentid
See the demo.
Results:
> Message | ID | ParentID
> :------ | :-- | :-------
> Parent | 123 |
> Child | 145 | 123
> Child | 234 | 123
> Child | 345 | 123
> Parent | 333 |
> Child | 100 | 333
> Child | 111 | 333
> Child | 567 | 333
> Child | 789 | 333
If the parents contain NULL at the parentid column instead of '', then the ORDER BY clause must be changed to:
order by isnull(parentid, id), parentid
The goal is to return values for id_num and county from table address_master (address_master has one record per id) if BOTH an id_num AND county value is not returned using the following query on address_history:
SELECT DISTINCT a.id_num, a.county
FROM address_history a
INNER JOIN (SELECT id_num, MIN(archive_job_tim) AS MaxEnrollDate
FROM address_history
GROUP BY id_num) b
ON (a.id_num = b.id_num AND a.archive_job_tim = b.MaxEnrollDate)
WHERE addr_cde = '*LHP'
Sample Data:
Table address_history (contains historical changes, multiple records per id are possible)
id_num | county | archive_job_tim
-------|--------|----------------
123 |012 |10/17/2001 10:48:38
123 |NULL |10/17/2001 09:50:02
123 |042 |11/17/2003 08:22:01
134 |NULL |12/10/2005 02:14:23
145 |534 |9/27/1996 00:00:00
Table address_master (contains only the most recent record for every id)
id_num | county | archive_job_tim
-------|--------|-----------------
123 |563 |12/22/2015 10:29:01
134 |734 |2/23/2005 07:21:15
145 |943 |10/22/1996 06:24:13
168 |012 |6/5/2017 08:01:22
197 |NULL |7/1/2017 10:16:02
Query result should be:
id_num | county
-------|--------
123 |012 (because it is the earliest record with a county for this id in address_history)
134 |734 (because the only record(s) in address_history has no county, returns record from address_master)
145 |534 (because it is the earliest record with a county for this id in address_history)
168 |012 (because no record exists in address_history for this id)
197 |NULL (because no record exists in address_history for this id)
Any help is appreciated. Thank you.
I think you are looking query as below:
Select top (1) with ties * from
(
Select *,'am' as Note from address_master
union all
Select *,'ah' as Note from address_history
) a where (a.Note = 'ah' and a.county is not null) or a.Note = 'am'
Order by Row_Number() over(partition by id_num order by archive_job_tim)
Output as below:
+--------+--------+-------------------------+------+
| id_num | county | archive_job_tim | Note |
+--------+--------+-------------------------+------+
| 123 | 12 | 2001-10-17 10:48:38.000 | ah |
| 134 | 734 | 2005-02-23 07:21:15.000 | am |
| 145 | 534 | 1996-09-27 00:00:00.000 | ah |
| 168 | 12 | 2017-06-05 08:01:22.000 | am |
| 197 | NULL | 2017-07-01 10:16:02.000 | am |
+--------+--------+-------------------------+------+
I want to display the subtraction of two columns. From the first column I need to get sum all value and substract with each value from the second column.
This is the table structure:
id | name | col1 | col2 | date
------------------------------------
432| xxx | 0 | 15 |2015-11-17
432| yyy | 10 | 30 |2015-11-19
432| zzz | 60 | 40 |2015-11-20
433| aaa | 0 | 60 |2015-11-17
433| bbb | 80 | 20 |2015-11-19
433| ccc | 60 | 10 |2015-11-20
Formula should go:
sum(col1) = 70 =>>> WHERE ID = 432
70 - col2 col3
-------------------------
=> 70 - 15 = 55
=> 70 - (30 + 15) = 25
=> 70 - (40 + 45) = -15
---------------------------
sum(col1) = 140 ===>> WHERE ID = 433
140 - col2 col3
-------------------------
=> 140 - 60 = 80
=> 140 - (60 + 20) = 60
=> 140 - (10 + 80) = 50
result is col3 and Output should be like as
id | name | col1 | col2 | col3 | date
-------------------------------------------
432| xxx | 0 | 15 | 55 | 2015-11-17
432| yyy | 10 | 30 | 25 | 2015-11-19
432| zzz | 60 | 40 | -15 | 2015-11-20
433| aaa | 0 | 60 | 80 | 2015-11-17
433| bbb | 80 | 20 | 60 | 2015-11-19
433| ccc | 60 | 10 | 50 | 2015-11-20
EDIT: What if I need the values vary depending on the group as a 432 and 433 id column.
Schema Info
DECLARE #TEST TABLE
(
id INT,
name VARCHAR(10),
col1 INT,
col2 int
)
INSERT INTO #TEST VALUES
(432,'xxx',0, 15 ),
(432,'yyy',10, 30 ),
(432,'zzz',60, 40 ),
(433,'aaa',0, 60 ),
(433,'bbb',80, 20 ),
(433,'ccc',60, 10 )
Query
SELECT T.id ,
T.name ,
T.col1 ,
T.col2 ,
SUM(T.col1) OVER( PARTITION BY T.id ORDER BY T.id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
- SUM(T.col2) OVER ( PARTITION BY T.id ORDER BY T.id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS col3
FROM #TEST T;
Results
id | name | col1 | col2 | col3 |
---------------------------------
432 | xxx | 0 | 15 | 55 |
432 | yyy | 10 | 30 | 25 |
432 | zzz | 60 | 40 | -15 |
433 | aaa | 0 | 60 | 80 |
433 | bbb | 80 | 20 | 60 |
433 | ccc | 60 | 10 | 50 |
SQL Fiddle
This should work:
declare #total int = (select sum(col1) from Table)
select id, name, col1, col2, #total - (select sum(col2) from Table where date <= T.date) as col3, date from Table T
I was assuming you want to substract every time the previous total (based on the date). I hope this is OK.
You can use simple select query with cross apply
SELECT ID
,NAME
,COL1
,COL2
,A.C1 - (
SUM(COL2) OVER (
ORDER BY ID
)
) AS COL3
FROM TABLE1 T1
CROSS APPLY (
SELECT SUM(COL1) AS C1
FROM TABLE1 T2
) A
You can use two subqueries in SELECT fields list.
With the first you'll get a sum of all rows of your table named yourtable, in the second you'll get a sum of all rows before the current. So you can subtract two values.
Try this:
SELECT T.id, T.name, T.col1, T.col2,
ISNULL(
(SELECT SUM(T2.col1) FROM yourtable T2)
,0) -
ISNULL(
(SELECT SUM(T3.col2) FROM yourtable T3
WHERE T3.id <= T.id)
,0) as col3,
t.date
FROM yourtable T
Go on Sql fiddle example
EDIT
SELECT T.id, T.name, T.col1, T.col2,
ISNULL(
(SELECT SUM(T2.col1) FROM yourtable T2 where T2.id = T.id)
,0) -
ISNULL(
(SELECT SUM(T3.col2) FROM yourtable T3
WHERE T3.id = T.id AND T3.date <= T.date)
,0) as col3,
t.date
FROM yourtable T
Go on Sql Fiddle edited example
Pay attention: A deep edit can be a different question. Two queries are differents
Pay attention: it's no good a field named ID with repeated values
I am using sqlserver and I have two table which contains below data. I need to select those matched rows without duplicate.
Table_A:
A_ID | Item_ID
--------------------
1 | 101
2 | 101
3 | 103
4 | 103
5 | 199
Table_B:
B_ID | Item_ID
--------------------
11 | 101
12 | 101
13 | 102
14 | 103
15 | 103
16 | 103
Expected Result:
A_ID | Item_ID | B_ID
----------------------
1 | 101 | 11
2 | 101 | 12
3 | 103 | 14
4 | 103 | 15
I tried:
SELECT A_ID, a.Item_ID, B_ID FROM Table_A a LEFT JOIN
Table_B b ON a.Item_ID = b.Item_ID
But it show all the possible records.
How can i display the expected result above?
Based on the result set you gave you want one unique record from B for each A, ignoring records in A for which there is no corresponding record in B. The following will work:
SELECT
AValues.A_ID,
AValues.Item_ID,
BValues.B_ID
FROM
(SELECT
A_ID,
Item_ID,
ROW_NUMBER() OVER(PARTITION BY Item_ID ORDER BY A_ID) ARowID
FROM
Table_A) AValues
INNER JOIN (SELECT
B_ID,
Item_ID,
ROW_NUMBER() OVER(PARTITION BY Item_ID ORDER BY B_ID) BRowID
FROM
Table_B) BValues ON AValues.Item_ID = BValues.Item_ID AND AValues.ARowID = BValues.BRowID