I have been searching in Google and SO for an answer to this but having a hard time. Not even sure if I am asking it correctly, but I am going to give it my best shot here:
My data:
Fruit | Attributes
-------------------
Apple | Dark Red
Apple | Green
Apple | Yellow
Apple | Light Red
Apple | Greenish Yellow
Apple | Dark Yellow
Apple | Brown
Banana | Yellow
Banana | Greenish Yellow
Banana | Dark Yellow
Banana | Yellow
Banana | Brown
Banana | Red
Banana | Black
What I would like to do is run a query that outputs how many attributes for all fruits (in this case just apples and bananas) that overlap.
Hope I've been clear... please let me know if I need to clarify.
Something like this?
SELECT DISTINCT ATTRIBUTE, FRUIT
FROM FRUIT_TABLE
WHERE ATTRIBUTE IN (
SELECT ATTRIBUTE
FROM FRUIT_TABLE
GROUP BY ATTRIBUTE
HAVING COUNT(DISTINCT FRUIT_NAME) > 1 )
ORDER BY ATTRIBUTE, FRUIT_NAME
I tried it with City and State in a similar way and it worked:
SELECT DISTINCT CITY, STATE
FROM ADDRESS
WHERE CITY IN (
SELECT CITY
FROM ADDRESS
GROUP BY CITY
HAVING COUNT(DISTINCT STATE) > 1)
ORDER BY CITY, STATE
BATH NB
BATH ON
BEDFORD NS
BEDFORD QC
BRANDON MB
BRANDON MT
Brampton NB
Brampton ON
... and so on
SELECT ATTRIBUTE, COUNT(*) FROM (
SELECT DISTINCT ATTRIBUTE, FRUIT
FROM FRUIT_TABLE
WHERE ATTRIBUTE IN (
SELECT ATTRIBUTE
FROM FRUIT_TABLE
GROUP BY ATTRIBUTE
HAVING COUNT(DISTINCT FRUIT_NAME) > 1 )
ORDER BY ATTRIBUTE, FRUIT_NAME ) AS RESULTS
GROUP BY ATTRIBUTE
Related
I have a column fruits and it has rows like
banana
pineapple
orange
grapes
apple
mango
pomegranate
Kiwi
grapefruit
peach
or maybe like this
pineapple
grapefruit
orange
grapes
apple
mango
pomegranate
Kiwi
banana
peach
I want to retrieve all that with grapefruit in the middle all the time like following no matter whether it has even or odd number of rows
banana
pineapple
orange
grapes
grapefruit
apple
pomegranate
Kiwi
mango
I know basic SQL query SELECT fruit FROM FRUITTABLE
but dont know further
You can order by is_even/is_odd on some enumeration. (here: the difference in row_number() over nothing)
\i tmp.sql
CREATE TABLE fruits(fruit text);
INSERT INTO fruits(fruit) VALUES
('banana') ,('pineapple') ,('orange') ,('grapes') ,('apple') ,('mango') ,('pomegranate') ,('Kiwi') ,('grapefruit') ,('peach')
;
with numbered AS (
select fruit, row_number() OVER () rn
FROM fruits
)
, gnum AS (
SELECT rn FROM numbered
WHERE fruit = 'grapefruit'
)
SELECT n.fruit, n.rn
FROM numbered n
JOIN gnum g ON true
ORDER BY ((n.rn - g.rn) %2), (n.rn <> g.rn)
;
Result:
CREATE TABLE
INSERT 0 10
fruit | rn
-------------+----
mango | 6
grapes | 4
Kiwi | 8
pineapple | 2
grapefruit | 9
banana | 1
orange | 3
apple | 5
pomegranate | 7
peach | 10
(10 rows)
Edit: the tie-breaker is not always correct (caused by modulo on negative numbers) A better order would be
ORDER BY (ABS(n.rn - g.rn) %2) , (n.rn <> g.rn) DESC
I think you should explain why you want to do this, maybe there is a better way to do obtain the result you want.
But I think that you could add a weight col in your table
and order by that value in the select.
Just take into consideration that whenever you add a new row you have to update that weights in order to maintain grapefruit in the middle.
And you have to define how to manage the pair numbers of rows.
Table with examples
SELECT *
FROM Fruits
ORDER BY Weight;
Could you do:
(select * from fruit where id < (select max(id)/2 from fruit))
union select * from fruit where id = grapefruit
union
(select * from fruit where id > (select max(id)/2 from fruit))
Or something like that. If you don't have an id you might have to use rownumber, but it should be doable.
I have two sql commands I want to combine. I have changed the variables I am actually using in an attempt make it simpler to explain.
I would like to get the name of all fruits and vegetables with the colors that are a favoriteColor of everyone who's age is equal to the given value.
Currently I have these queries split up and I get the favorite color of people with SELECT favoriteColor FROM people WHERE age = ? and then I get all the fruits and vegetables where the color matches the favoriteColor of each person.
I get the matching fruits and vegetables like this:
SELECT * FROM ((SELECT 1 as type, name FROM fruits WHERE color = ?)
UNION ALL
(SELECT 2 as type, name FROM vegetables WHERE color = ?)) results
I basically want something like this, but I haven't been able to get it to work and I also do not want to have to run the same SELECT query twice:
SELECT * FROM ((SELECT 1 as type, name FROM fruits WHERE color =
(SELECT favoriteColor FROM people WHERE age = ?))
UNION ALL
(SELECT 2 as type, name FROM vegetables WHERE color =
(SELECT favoriteColor FROM people WHERE age = ?))) results
And I don't mind if I get duplicated fruits and vegetables, I need the duplicates for my situation.
For example:
If there are 2 people who are 30 years old and both of them like the color red, I want to get all fruits and vegetables that are red twice.
If there are 2 people who are 10 years old and one of them likes the color red and the other one also likes the color green, I want to get all fruits and vegetables that are red and green.
Not sure why you thought you had to test the colour in the union since the driver is people. And I have guessed what our output should be.
create table people(id int,name varchar(10),colour varchar(1),age int);
insert into fruits values
(1,'a','a'),(2,'b','a'),(3,'b','b'),(4,'b','c');
insert into vegetables values
(1,'t','a'),(2,'t','u'),(3,'v','v'),(4,'v','w');
insert into people values
(1,'aa','a',10),(2,'bb','b',10),(3,'cc','c',10),(4,'dd','c',11);
select p.name,p.age,p.name,s.`type`,s.name,s.colour
from people p
join
(
select 1 as type, name,colour from fruits
union
select 2 as type, name,colour from vegetables
) s
on s.colour = p.colour
where p.age = 10;
+------+------+------+------+------+--------+
| name | age | name | type | name | colour |
+------+------+------+------+------+--------+
| aa | 10 | aa | 2 | t | a |
| aa | 10 | aa | 1 | b | a |
| aa | 10 | aa | 1 | a | a |
| bb | 10 | bb | 1 | b | b |
| cc | 10 | cc | 1 | b | c |
+------+------+------+------+------+--------+
5 rows in set (0.00 sec)
i don't know but the simplied version may be
SELECT * FROM ((SELECT 1 as type, name, color FROM fruits WHERE color = ?) UNION ALL
(SELECT 2 as type, name, color FROM vegetables WHERE color = ?)) results
where results.color= (SELECT favoriteColor FROM people WHERE age = ?)
sorry for indentation
I'd do it as a pair of unions to create one unified dataset, joined to another (then filtered) dataset:
SELECT * FROM
(
SELECT 1 as type, name, color FROM fruits
UNION ALL
SELECT 2 as type, name, color FROM vegetables
) plants pl
INNER JOIN
people pe ON pl.color = pe.favoriteColor
WHERE
pe.age = 30
If you want different columns out of fruit and veg, and there might not be a fruit or veg row for a given color:
SELECT * FROM
people pe
LEFT JOIN fruits f on pe.favoriteColor = f.color
LEFT JOIN veg v on pe.favoriteColor = f.color
WHERE
pe.age = 30
But bear in mind that multiple fruits or veg of a given color will cause the result set to multiply in duplicate for the other plant, which could become a nightmare to deal with on the front end
Let's say I have a table that lists cars by user.
id | user_id | color
1 | 1 | red
2 | 1 | red
3 | 2 | blue
4 | 2 | red
5 | 3 | red
Now, I want to know how much red cars each client has, so I've done this SQL :
SELECT user_id, COUNT(color)
FROM cars
WHERE color = 'red'
GROUP BY user_id
Which lists me :
1 | 2
2 | 1
3 | 1
But what I really want is the count of each count. Something like :
Users with 1 red car : 2
Users with 2 red car : 1
...
So is there a way to count my select which already includes a count() grouped by ?
Thank you in advance !
Use an aggregation of aggregations:
SELECT redCount, COUNT(*)
FROM (SELECT user_id, COUNT(color) as redCount
FROM cars
WHERE color = 'red'
GROUP BY user_id
) uc
GROUP BY redCount;
I am trying to condense an order by 2 columns query, into an order by 1 column query with a breakdown column. If this has a proper name I would greatly appreciate knowing what it is!
Example:
ocean
name | type | colour
fishy | salmon | red
splishy | salmon | red
splashy | salmon | pink
sploshy | salmon | pink
floaty | whale | blue
humprhey | whale | grey
wilson | whale | grey
Looking for (I'm not sure what doing this is called):
type | count | colour breakdown
salmon| 4 | 2 red, 2 pink
whale | 3 | 1 blue, 2 grey
Preferentially with minimal use of string functions.
Not sure how to proceed from:
(Order by one column)
SELECT o.type, count(*)
FROM ocean o
GROUP BY `type`
type | count
salmon| 4
whale | 3
(Order by two columns)
SELECT o.type, o.colour, count(*)
FROM ocean o
GROUP BY `type`, `colour`
type | colour | count
salmon| red | 2
salmon| pink | 2
whale | blue | 1
whale | grey | 2
Ugly, untested, but may just do what you want:
SELECT type, SUM(color_count),
GROUP_CONCAT(CONCAT(color_count, ' ', colour) SEPARATOR ', ') AS colour_breakdown
FROM (
SELECT type, colour, COUNT(colour) AS colour_count
FROM ocean
GROUP BY type, colour
) AS subt
GROUP BY type
Using your second query as a data source, you can use group_concat() to get the output you want:
select type, sum(`count`), group_concat(colBreak separator ',') as color_breakdown
from
(
SELECT
o.type,
o.colour,
count(o.type) as `count`,
concat(o.colour, ' ', count(o.type)) as colBreak
FROM ocean o
GROUP BY `type`, `colour`
) as a
group by type;
I have two tables. One has all options and one has the user selected options as well as some they created which may not be in the options table.
I need to union the data so I get back a result set which includes all of the options, as well as the users options and somehow flag which are user only and which overlap with the main options data...
Example...
OPTIONS
`COLOR` | `ANIMAL`
---------------------
RED | DOG
BLUE | DOG
GREEN | DOG
YELLOW | CAT
PINK | CAT
ORANGE | CAT
USER SELECTED OPTIONS
`COLOR` | `ANIMAL`
------------------
GREEN | SNAKE
BLUE | DOG
PINK | CAT
PURPLE | CAT
My results need to look like...
`COLOR` | `ANIMAL`| `DUPLICATE_OR_NEW`
----------------------------------------
RED | DOG | 0
BLUE | DOG | 1
GREEN | DOG | 0
YELLOW | CAT | 0
PINK | CAT | 1
ORANGE | CAT | 0
PURPLE | CAT | 1
GREEN | SNAKE | 1
The sort order does not matter in this scenario. I was trying with UNIONS but I think I need to do it by joining the two tables together. I am not coming up with a solution so far.
This may be called cheating but it will work
SELECT COLOR, ANIMAL, sum(DUPLICATE_OR_NEW)
FROM
(
SELECT COLOR, ANIMAL, 1 as DUPLICATE_OR_NEW FROM options
UNION ALL
SELECT COLOR, ANIMAL, 2 as DUPLICATE_OR_NEW FROM UserSelection
) as UTable
GROUP BY COLOR, ANIMAL
-- 1 = unchosen option
-- 2 = new user added option
-- 3 = option exsisted chosen by user
see SQL Fiddle http://sqlfiddle.com/#!2/01c79/2
Another way to approach this:
select color, animal, 1 as duplicate_or_new
from UserSelected
union all
select color, animal, 0 as duplicate_or_new
from options o
where not exists (select 1 from UserSelected us where us.color = o.color and us.animal = o.animal)
The correct way to do it with the union all/group by:
select color, animal, max(which) as duplicate_or_new
from (select color, animal, 1 as which
from UserSelected
union all
select color, animal, 0 as which
from options
) t
group by color, animal
The following query creates two separate flags:
select color, animal, max(isUser) as IsUser, max(isOption) as IsOption
from (select color, animal, 1 as IsUser, 0 as IsOption
from UserSelected
union all
select color, animal, 0 as IsUser, 1 as IsOption
from options
) t
group by color, animal
You can put them in a case statement to format the information:
(case when max(isUser) = 1 and max(isOption) = 1 then 'both'
when max(isUser) = 1 then 'user'
when max(isOption) = 1 then 'option'
else 'impossible'
end)