I have a table with 3 columns as below
id a b
=================
1 1 2
2 1 3
3 1 4
4 2 4
5 2 5
6 3 4
7 3 5
I wanna show the result
if a column or b column is duplicated,
I have try to use Group by ( a,b) but result is not I want.
I wanna Group by (a) and show grouped first row A,B and B is not duplicated
In my example, A will grouped into { 1, 2 ,3 },
and B will show {2 , 4, 5} not {2,4,4} because 4,4 is duplicated
id a b
=================
1 1 2
4 2 4
7 3 5
How do I do for this ?
Sorry, I’m not good at English.
Thx for help.
This code goes from your example data to your example results. Seems strange though and I doubt this is what you're looking for. If you give more detail, then you can get a better answer.
CREATE TABLE Example
(
id INT NOT NULL,
a INT NOT NULL,
b INT NOT NULL
)
GO
INSERT Example
VALUES
(1, 1, 2)
, (2, 1, 3)
, (3, 1, 4)
, (4, 2, 3)
, (5, 2, 4)
, (6, 3, 4)
SELECT
MIN(id) AS id
, a
, MIN(b) AS b
FROM
Example
GROUP BY
a
DROP TABLE Example
Related
I am trying to process data within the same table.
Input:
Table
id sort value
1 1 1
2 1 8
3 2 0
4 1 2
What I want to achieve is obtain for each id, the first encountered value for all value equal to its sort, and this ordered by id.
Output
Table
id sort value new
1 1 1 1
2 1 8 1
3 2 0 0
4 1 2 1
I tried to self join the table, but I constantly get relation not found. I tried with a case statement but I don't see how can I connect to the same table, I get the same error, relation not found.
The beauty of SQL is that many requirements (yours included) can be verbosely described in very similar way they are finally coded:
with t(id, sort, value ) as (values
(1, 1, 1),
(2, 1, 8),
(3, 2, 0),
(4, 1, 2)
)
select t.*
, first_value(value) over (partition by sort order by id) as "new"
from t
order by id
id
sort
value
new
1
1
1
1
2
1
8
1
3
2
0
0
4
1
2
1
fiddle
I would like to query hierarchy results ordered by depth first without the use of SQL's heiarchyid built in function. Essentially, I am hoping to accomplish the depth ordering without any fancy functions.
I have provided a temp table below that contains these records:
Id
p_Id
order1
name1
1
null
1
josh
2
null
2
mary
3
null
3
george
4
1
1
joe
5
1
2
jeff
6
2
1
marg
7
2
2
moore
8
2
3
max
9
3
1
gal
10
3
2
guy
11
4
1
tod
12
4
2
ava
13
9
1
ron
14
9
2
bill
15
9
100
pat
where p_Id is the id of the parent record, and order1 is essentially just the ordering of which the depth first output should be displayed. To show why my query does not fully work, I made the order1 of the last record 100 instead of say, 3. However this should not ultimately matter since 100 and 3 both come after the previous order1 value, 2.
An example of a correct result table is shown below:
Id
p_Id
order1
name1
Descendants
1
null
1
josh
josh
4
1
1
joe
josh/joe
11
4
1
tod
josh/joe/tod
12
4
2
ava
josh/joe/ava
5
1
2
jeff
josh/jeff
2
null
2
mary
mary
6
2
1
marg
mary/marg
7
2
2
moore
mary/moore
8
2
3
max
mary/max
3
null
3
george
george
9
3
1
gal
george/gal
13
9
1
ron
george/gal/ron
15
9
2
bill
george/gal/bill
14
9
100
pat
george/gal/pat
10
3
2
guy
george/guy
Where an example of my results are shown below:
Id
p_Id
order1
name1
Descendants
levels
1
null
1
josh
josh
.1
4
1
1
joe
josh/joe
.1.1
11
4
1
tod
josh/joe/tod
.1.1.1
12
4
2
ava
josh/joe/ava
.1.1.2
5
1
2
jeff
josh/jeff
.1.2
2
null
2
mary
mary
.2
6
2
1
marg
mary/marg
.2.1
7
2
2
moore
mary/moore
.2.2
8
2
3
max
mary/max
.2.3
3
null
3
george
george
.3
9
3
1
gal
george/gal
.3.1
13
9
1
ron
george/gal/ron
.3.1.1
15
9
100
pat
george/gal/pat
.3.1.100
14
9
2
bill
george/gal/bill
.3.1.2
10
3
2
guy
george/guy
.3.2
where I have created a levels column that essentially concatenates the order1 values and separates them with a period. This almost returns the correct results, but due to the fact that I am ordering by this string (of numbers and periods), the levels value of .3.1.100 will come before .3.1.2 , which is not what the desired output should look like. I am sure there is a different method to return the correct depth order. See below for the code that generates a temp table, and the code that I used to generate the incorrect output that I have so far.
if object_id('tempdb..#t1') is not null drop table #t1
CREATE TABLE #t1 (Id int, p_Id int, order1 int, name1 varchar(150))
INSERT into #t1 VALUES
(1, null, 1, 'josh'),
(2, null, 2, 'mary'),
(3, null, 3, 'george'),
(4, 1, 1, 'joe'),
(5, 1, 2, 'jeff'),
(6, 2, 1, 'marg'),
(7, 2, 2, 'moore'),
(8, 2, 3, 'max'),
(9, 3, 1, 'gal'),
(10, 3, 2, 'guy'),
(11, 4, 1, 'tod'),
(12, 4, 2, 'ava'),
(13, 9, 1, 'ron'),
(14, 9, 2, 'bill'),
(100, 9, 100, 'pat');
select * from #t1
-- Looking to generate heiarchy results ordered by depth --
; with structure as (
-- Non-recursive term.
-- Select the records where p_Id is null
select p.Id,
p.p_Id,
p.order1,
p.name1,
cast(p.name1 as varchar(64)) as Descendants,
cast(concat('.', p.order1) as varchar(150)) as levels
from #t1 p
where p.p_Id is null
union all
-- Recursive term.
-- Treat the records from previous iteration as parents.
-- Stop when none of the current records have any further sub records.
select c.Id,
c.p_Id,
c.order1,
c.name1,
cast(concat(p.Descendants, '/', c.name1) as varchar(64)) as Descendants,
cast(concat(p.levels, '.', c.order1) as varchar(150)) as levels
from #t1 c -- c being the 'child' records
inner join structure p -- p being the 'parent' records
on c.p_Id = p.Id
)
select *
from structure
order by replace(levels, '.', '') asc
Take II. As pointed out by OP my original answer fails for more than 10 children. So what we can do (OP's suggestion) is pad the values out with zeros to a constant length. But what length? We need to take the largest number of children under a node and add this to the largest value or order, so for the example provided this is 100 + 3, and then take the length of that (3) and pad every order with zeros to 3 digits long. This means we will always be ordering as desired.
declare #PadLength int = 0;
select #PadLength = max(children)
from (
select len(convert(varchar(12),max(order1)+count(*))) children
from #t1
group by p_Id
) x;
-- Looking to generate heiarchy results ordered by depth --
with structure as (
-- Non-recursive term
-- Select the records where p_Id is null
select
p.Id [Id]
, p.p_Id [ParentId]
, p.order1 [OrderBy]
, p.name1 [Name]
, cast(p.name1 as varchar(64)) Descendants
, concat('.', right(replicate('0',#Padlength) + convert(varchar(12),p.order1), #PadLength)) Levels
from #t1 p
where p.p_Id is null
union all
-- Recursive term
-- Treat the records from previous iteration as parents.
-- Stop when none of the current records have any further sub records.
select
c.Id,
c.p_Id,
c.order1,
c.name1,
cast(concat(p.Descendants, '/', c.name1) as varchar(64)),
concat(p.levels, '.', right(replicate('0',#Padlength) + convert(varchar(12),c.order1), #PadLength))
from #t1 c -- c being the 'child' records
inner join structure p on c.p_Id = p.Id -- p being the 'parent' records
)
select *
from structure
order by replace(levels, '.', '') asc;
Note: This answer fails in the case when there are more than 10 children under a particular node. Leaving for interest.
So this issue you have run into is that you are ordering by a string not a number. So the string 100 comes before the string 2. But you need to order by a string to take care of the hierarchy, so one solution is to replace order1 with row_number() based on the order1 column while its still a number and use the row_number() to build your ordering string.
So you replace:
cast(concat(p.levels, '.', c.order1) as varchar(150)) as levels
with
cast(concat(p.levels, '.', row_number() over (order by c.Order1)) as varchar(150))
giving a full query of
with structure as (
-- Non-recursive term.
-- Select the records where p_Id is null
select p.Id,
p.p_Id,
p.order1,
p.name1,
cast(p.name1 as varchar(64)) as Descendants,
cast(concat('.', p.order1) as varchar(150)) as levels
from #t1 p
where p.p_Id is null
union all
-- Recursive term.
-- Treat the records from previous iteration as parents.
-- Stop when none of the current records have any further sub records.
select c.Id,
c.p_Id,
c.order1,
c.name1,
cast(concat(p.Descendants, '/', c.name1) as varchar(64)) as Descendants,
cast(concat(p.levels, '.', row_number() over (order by c.Order1)) as varchar(150))
from #t1 c -- c being the 'child' records
inner join structure p -- p being the 'parent' records
on c.p_Id = p.Id
)
select *
from structure
order by replace(levels, '.', '') asc;
Which returns the desired results.
Note: good question, well written.
I would like a simple query to solve this.
We have a simple table with 4 columns for merging client data. We have to create a loop to transverse the data until the ToClient cannot be found in the FromClient Row. We have one person that has been merged 5 times.
FromClient# ToClient# Userid Timestamp
1 2
2 3
3 4
4 5
5 6
7 8
What I want is a table created that looks like the following, so it is a simple join for reporting.
FromClient# ToClient#
1 6
2 6
3 6
4 6
5 6
7 8
Any pointers would be great.
Thanks.
Try this using Recursive Common Table Expression (RCTE):
with
mytab (FromClient#, ToClient#) as
(
values
(1, 2)
, (2, 3)
, (3, 4)
, (4, 5)
, (5, 6)
, (7, 8)
)
, t (FromClient#, ToClient#) as
(
select FromClient#, ToClient#
from mytab a
where not exists (select 1 from mytab b where b.FromClient# = a.ToClient#)
union all
select a.FromClient#, t.ToClient#
from t, mytab a
where a.ToClient# = t.FromClient#
)
select *
from t
order by FromClient#;
I have a table with colors:
COLORS
idColor Name
------- ------
4 Yellow
5 Green
6 Red
And I have another table with data:
PRODUCTS
idProduct idCategory idColor
--------- ---------- -------
1 1 4
2 1 5
3 1 6
4 2 10
5 2 11
6 2 12
7 3 4
8 3 5
9 3 8
10 4 4
11 4 5
12 4 6
13 5 4
14 6 4
15 6 5
I just want return rows from Products when the idColor values from table Colors (4, 5, 6) are present in the second table and IdCategory has exactly 3 elements with the same idColor values 4, 5, 6.
For this example, The query should return:
IdCategory
----------
1
4
Try this:
SELECT idCategory
FROM PRODUCTS
GROUP BY idCategory
HAVING COUNT(*) = 3
AND COUNT(DISTINCT CASE WHEN idColor IN (4,5,6) THEN idColor END) = 3
Here is a demo for you to try.
UPDATED
If you want to dynamically filter the results depending on the values of the table `COLOR
SELECT idCategory
FROM PRODUCTS P
LEFT JOIN (SELECT idColor, COUNT(*) OVER() TotalColors
FROM COLORS) C
ON P.idColor = C.idColor
GROUP BY idCategory
HAVING COUNT(*) = MIN(C.TotalColors)
AND COUNT(DISTINCT C.idColor) = MIN(C.TotalColors)
Here is a fiddle with this example.
You can use aggregates to make sure it has all 3 colors, and also to make sure it DOESN'T have any other colors. Something like this:
SELECT *
FROM
(
SELECT idCategory
, SUM(CASE WHEN idColor IN (4, 5, 6) THEN 1 ELSE 0 END) AS GoodColors
, SUM(CASE WHEN idColor NOT IN (4, 5, 6) THEN 1 ELSE 0 END) AS BadColors
FROM Products
GROUP BY idCategory
) t0
WHERE GoodColors = 3 AND BadColors = 0
Note, if the 4, 5, 6 is found more than once per idCategory then a different technique must be employed. But from your example, it doesn't appear that way.
I am guessing that you would like to perform this task based on data in a table, rather than hardcoding the values 4, 5, and 6 (like in some of the answers given). To that end, in my solution I created a dbo.ColorSets table that you can fill with as many different sets of colors as you want, then run the query and see all the product Categories that match those color Sets. The reason I didn't just use your dbo.Color table is that it appeared to be the lookup table, complete with color names, so it didn't seem like the right one to be picking out a particular set of colors rather than the entire list possible.
I used a technique that will maintain good performance even on huge amounts of data, as compared to other query methods that use aggregates exclusively. No matter what method one uses, this task will pretty much always require a scan of the entire Products table because you can't compare all the rows without, well, comparing all the rows. But the JOIN is on indexable columns and is only for the candidates that have a very good chance of being proper matches, so the amount of work required is greatly reduced.
Here's what the ColorSets table looks like:
CREATE TABLE dbo.ColorSets (
idSet int NOT NULL,
idColor int NOT NULL,
CONSTRAINT PK_ColorSet PRIMARY KEY CLUSTERED (idSet, idColor)
);
INSERT dbo.ColorSets
VALUES
(1, 4),
(1, 5),
(1, 6), -- your color set: yellow, green, and red
(2, 4),
(2, 5),
(2, 8) -- an additional color set: yellow, green, and purple
;
And the query (see this working in a SqlFiddle):
WITH Sets AS (
SELECT
idSet,
Grp = Checksum_Agg(idColor)
FROM
dbo.ColorSets
GROUP BY
idSet
), Categories AS (
SELECT
idCategory,
Grp = Checksum_Agg(idColor)
FROM
dbo.Products
GROUP BY
idCategory
)
SELECT
S.idSet,
C.idCategory
FROM
Sets S
INNER JOIN Categories C
ON S.Grp = C.Grp
WHERE
NOT EXISTS (
SELECT *
FROM
(
SELECT *
FROM dbo.ColorSets CS
WHERE CS.idSet = S.idSet
) CS
FULL JOIN (
SELECT *
FROM dbo.Products P
WHERE P.idCategory = C.idCategory
) P
ON CS.idColor = P.idColor
WHERE
CS.idColor IS NULL
OR P.idColor IS NULL
)
;
Result:
idSet idCategory
1 1
2 3
1 4
If I understand your question, this should do it
select distinct idCategory
from Products
where idColors in (4,5,6)
I have a table with part of data like below . I have done order by on edition_id .
Now there is further requirement of ordering laungauge_id which depends on value of edition_id.
Edition_id refers to city from which a newspaper is published.
Language_id refers to different languages in which newspaper is
published.
So suppose edition_id = 5 it means New Delhi.
For New Delhi language_id are 13(English ), 5 (Hindi) ,1(Telugu ),4(Urdu).
What i want is to display for New Delhi , is display all English articles first , followed by hindi , followed by Telugu followed by Urdu.
If edition_id=1 then order of language_id should be 13,1,2.
Similarly ,
If edition_id=5 then order of language_id should be 13,5,1,4
Right now what I have is
Edition_id | Language_id
1 1
1 2
1 13
1 1
1 13
1 2
5 4
5 1
5 1
5 4
5 13
5 5
5 13
What is required
Edition_id | Language_id
1 13
1 13
1 1
1 1
1 2
1 2
5 13
5 13
5 5
5 1
5 1
5 4
5 4
How to do this ? Please help.
Is something like this possibe
Select * from <table>
order by edition_id ,
case when edition=6 then <order specified for language_id ie 13,5,1,4>
I would create a supplementary ranking table. I would then JOIN to provide your sort order. Eg:
EDITION_SORT_ORDER
EDITION_ID LANGUAGE_ID RANK
---------- ----------- ----
1 13 1
1 1 2
1 2 3
5 13 1
5 5 2
5 1 3
5 4 4
Using this table in a query might look like this:
SELECT E.EDITION_ID, E.LANGUAGE_ID
FROM <TABLE> E LEFT OUTER JOIN EDITION_SORT_ORDER S ON
E.EDITION_ID = S.EDITION_ID AND
E.LANGUAGE_ID = S.LANGUAGE_ID
ORDER BY S.RANK
This way you can add other rules in future, and it isn't a huge mess of CASE logic.
Alternatively, if you want to avoid a JOIN, you could create a stored function which did a similar lookup and returned a rank (based on passed parameters of EDITION_ID and LANGUAGE_ID).
If you must use CASE, then I'd confine it to a function so you can re-use the logic elsewhere.
If there is no mathematical logic behind it, I would insert another column that can be used for proper sorting.
If you cannot do this, you can simply type out the rules for the relation like this:
Order By Edition_Id,
case Edition_id
when 1 then
case Language_id
when 13 then 1
when 1 then 2
when 2 then 3
end
when 5 then
case Language_id
when 13 then 1
when 5 then 2
when 1 then 3
when 4 then 4
end
end
without a fixed order colum you could things like that, but the logic is not comprehensible.
Assuming first criteria is length of Language_id,
Second is Edition_id= Language_id,
rest is order of Language_id it could or work this way:
Declare #t table(Edition_id int, Language_id int)
insert into #t values
(1, 1),
(1, 2),
(1, 13),
(1, 1),
(1, 13),
(1, 2),
(5, 4),
(5, 1),
(5, 1),
(5, 4),
(5, 13),
(5, 5),
(5, 13);
Select * from #t
order by Edition_id,Case when len (Cast(Language_ID as Varchar(10)))=1 then '1' else '0' end
+case when Edition_id=Language_id then '0' else '1' end
,Language_ID
You've probably considered this but if your desired ordering is always based of the actual alphabetical name of the language then there would usually be a table with the language description that you could join with and then sort by. I base this on your quote below.
...English articles first , followed by hindi , followed by Telugu
followed by Urdu.
SELECT E.EDITION_ID, E.LANGUAGE_ID, LN.LANGUAGE_NAME
FROM <TABLE> E LEFT OUTER JOIN <LANGUAGE_NAMES> LN ON
E.LANGUAGE_ID = LN.LANGUAGE_ID
ORDER BY 1, 3