MS Access query displays duplicate record that matches value in another column - sql

I need help to query a table for distinct records by TRANS_CODE that matches value in the ITEM column. Any help would be very much appreciative.
Here is an example of the table.
ID TRANS_CODE ITEM
1 CD50 Red
2 TN30 Blue
3 RC50 Green
4 WC70 White
5 PT30 Blue
6 AB60 White
7 RC50 Red
8 WC70 Blue
9 TN30 Green
10 PT30 Green
The logic for displaying duplicate TRANS_CODE is driven by the ITEM column. The first logic for duplicate TRANS_CODE is to show ITEM that is Blue and the secord is show
ITEM that is Green. For example...
Duplicate TRANS_CODE that has ITEM, Blue, Green, and Red: Show record with Blue only
Duplicate TRANS_CODE that has ITEM, Green, Red, and White: Show record with Green only
The result should generate this list....
ID TRANS_CODE ITEM
1 CD50 Red
2 TN30 Blue
3 RC50 Green
8 WC70 Blue
5 PT30 Blue
6 AB60 White

You can map your colors to Numbers using switch. Then using two inline queries joined together you can get the answer you're looking for.
Technically you don't need to use the switch because the colors are in alpha order but just in case your real values weren't
SELECT t.id,
t.transcode,
t.item
FROM (SELECT transcode,
item,
id,
Switch([ITEM] = "Blue", 1, [ITEM] = "Green", 2, [ITEM] = "Red", 3
,
[ITEM] =
"White", 4) AS weight
FROM table2) AS t
INNER JOIN (SELECT transcode,
MIN(Switch([ITEM] = "Blue", 1, [ITEM] = "Green", 2,
[ITEM] =
"Red", 3,
[ITEM] =
"White", 4)) AS weight
FROM table2
GROUP BY transcode) AS t2
ON ( t.weight = t2.weight )
AND ( t.transcode = t2.transcode )
ORDER BY t.id
This gives you the output below, I hope that ID 8 being after 6 instead of between 3 and 5 works for you
id transcode item
1 CD50 Red
2 TN30 Blue
3 RC50 Green
5 PT30 Blue
6 AB60 White
8 WC70 Blue
Note: you can replace MIN(Switch... with FIRST(Switch... which may improve performance

You should try this:
select
(select ID from sometable as t2 where t2.trans_code = t1.trans_code and t2.item = Min(t1.Item)),
t1.trans_code,
Min(t1.item)
from sometable as t1
group by trans_code
order by 1
As you did not specify which color should have preference, I set the preference alphabetically (Blue, Green, Red and White). That's hat I could capture from your expected output.

Related

How to filter out all records that have duplicates in SQL?

Trying to get this result from a table with duplicates
red
red
red
blue
green
to
blue
green
Totally omitting all the records that has duplicates and only bringing in the unique records
Use GROUP BY and HAVING clause...
select color
from table1
group by color
having count(color) = 1
If you need more than just the colours.
select *
from paintmess
where colour in (
select colour
from paintmess
group by colour
having count(*)=1
);
id
colour
4
blue
5
green
db<>fiddle here

Select rows that belong to ONLY one category among many

Let's say there is this table colors
id
source
1
red
1
green
1
orange
2
red
2
red
3
black
3
green
4
red
5
green
What I want is the list of all id that have as only source the value 'red', so 2 and 4.
To be clear
select distinct id from colors where source = 'red'
would give 1,2 and 4, where 1 has 'green' and 'orange' in addition to 'red', so no.
Here the SQL to create the table
create temp table colors as
select *
from (values (1, 'red'),(1, 'green'),(1, 'orange'),(2,'red'),(2, 'red'),(3, 'black'),(3,'green'),(4,'red'),(5,'green'))
as t (id,source)
How to query this?
Use aggregation:
select id
from t
group by id
having count(*) filter (where color = 'red') = count(*);
I managed to find a query, but it seems so complicated and unpractical:
with colors_sint as (
--This is the list of distinct sources for every id
select id, source
from colors
group by id, source
), only_red as (
--Here I check which id has only one distinct source
select id, count(*) as n_sources
from colors_sint
group by id
having count(*) = 1
)
--among those id that have only one source, I take only those that have only red as source
select id
from colors_sint
where id in (select id from only_red)
and "source" = 'red'
Maybe someone has better ideas?

SQL Query Max Value Across Multiple Columns Multiple Rows

I need to write a sql query that will return the row that has the max value per user id.
In my table I have 5 columns (Blue, Red, Green, Blue, Orange, Yellow) that store a numeric value. And in my table a user can appear on multiple rows.
For each user id, I need to determine which of the 5 columns (Blue, Red, Green, Blue, Orange, Yellow) has the highest value per user id. I have tired a few things, but am stuck.
If I need to provide additional information, please let me know.
See table below
If you want to get fancy you can look into Using GROUP BY with ROLLUP, CUBE, and GROUPING SETS on groups but a simple approach is to flatten the list. You can use a pivot or union like example below. Then use row_number to get the first in the list.
declare #tbl table (UserId int, Blue int, Red int, Green int, Orange int, yellow int)
insert into #tbl (UserId, Blue, Red, Green, Orange, Yellow)
values
(1, 1,9,4,3,4),
(2, 2,5,4,3,5),
(3, 3,4,9,3,3),
(4, 9,4,6,3,9),
(5, 2,4,5,2,9)
;
with flattenedCte as (
select UserId, Blue [Count], 'Blue' Color from #tbl
union
select UserId, Red [Count], 'Red' Color from #tbl
union
select UserId, Green [Count], 'Green' Color from #tbl
union
select UserId, Orange [Count], 'Orange' Color from #tbl
union
select UserId, Yellow [Count], 'Yellow' Color from #tbl
)
,Sub as (
select
UserId,
Color,
max([Count]) [Max of Count],
ROW_NUMBER() over (partition by UserId order by max([Count]) desc) [Row number]
from flattenedCte
group by UserId,Color
)
select * from Sub where [Row number] = 1
could be using case when
select
user_id
, case when (blue > Red AND Blue > Green AND Blue > Orange AND Blue > Yellow) THEN Blue ELSE null END
, case when (Red > Blue AND Red > Green AND Red > Orange AND Red > Yellow) THEN Red ELSE null END
, case when (Green > Blue AND Green > Red AND Green > Orange AND Green > Yellow) THEN Green ELSE null END
, case when (Orange > Blue AND Orange > Red AND Orange > Green AND Orange > Yellow) THEN Orange ELSE null END
, case when (Yellow > Blue AND Yellow > Red AND Yellow > Green AND Yellow > Orange) THEN Yellow ELSE null END
from my_table
In your case maybe a case when coupled with a subtable might help, altough there might be a better solution out there.
This post here might help you out.

How to not lose records in full join

Let's say I have two tables; table A and table shown below:
A
Color ID
Blue 1
Green 2
Red 3
B
Color ID
Blue 1
Brown 2
Red 3
If I were to attempt to join them using a full join, the result would depend on which table I use in the select statement. For example the following query would produce the following result
select A.color, count(*)
from A
full join B on a.color = B.color
group by 1
order by 1
color count
Blue 1
Green 1
Red 1
1
If I decided to use B.color in the select statement instead of A.color, I would get the result below:
color count
Blue 1
Brown 1
Red 1
1
How would I get the resultset to include all values for color. I know I could accomplish using unionall, and I could use a case statement in the select statement to use one when the other is null, but is there another cleaner way to accomplish this?
Thanks,
Ben
Use coalesce to pick up the value from the other table in case the value exists in one table and not the other.
select coalesce(A.color,B.color) as color, count(*)
from A
full join B on a.color = B.color
group by 1
order by 1

Select average column value

I have a table containing order details. I would like to be able to select the average attribute for a certain item.
For example, select "item a", now find the average color of "item a". If there were 10 orders of "item a" and the colors ordered broke down as follows:
4 - black
2 - blue
2 - red
1 - orange
1 - white
I would like for it to return "black". Is there any such statement that could do that?
Also, would it then be possible to weigh the average, for example giving the last 3 orders of "item a" a weight of 2, instead of 1. So if the last 3 orders were all yellow, it would essentially count as 6?
You can group by on color, and then select the first row:
select color
from OrderLines
where ItemId = 'item a'
group by
color
order by
count(*) desc
limit 1
You could give some rows a higher weight with a subquery. This one gives the last 3 orders a higher weight:
select color
from (
select o1.color
, case when
(
select count(*)
from OrderLines o2
where o1.item = o2.item
and o1.OrderDt < o2.OrderDt
) < 3 then 2 else 1 end as weight
from OrderLines o1
)
where Item = 'item a'
group by
color
order by
sum(weight) desc
limit 1