for example this is my data
info
----
id name eating andSaying
--- ---- ------ ---------
1 aman mango with sister amanzing mango
2 ramesh mango via mouth wow its really good
3 aman guava with jimmy yoyo
4 ramesh pineapple yummy
Now i want a single query where i can fetch those rows who is having common eating value (table name eating) for example where name is aman and ramesh who is having same eating then show the rows
info
-----
id name eating andSaying
--- ---- ------ ---------
1 aman mango with sister amanzing mango
2 ramesh mango via mouth wow its really good
i have tried this query but it is NOT Working
SELECT *
FROM info a1
JOIN info a2
ON a1.name!= a2.name
AND a1.eating (get first array before "space"mango ) = a2.eating(get first array before "space" mango )
How to get the two rows if eating on first letter is same?
it should reflect two rows like this
info
-----
id name eating andSaying
--- ---- ------ ---------
1 aman mango with sister amanzing mango
2 ramesh mango via mouth wow its really good
To get the eating values related to more than one name values you can use:
SELECT eating
FROM info
GROUP BY eating
HAVING COUNT(DISTINCT name) > 1
Output:
eating
------
mango
Use the above query as a derived table and join back to the info table to get the expected result set:
SELECT i1.*
FROM info AS i1
JOIN (
SELECT eating
FROM info
GROUP BY eating
HAVING COUNT(DISTINCT name) > 1
) AS i2 ON i1.eating = i2.eating
Edit:
To get matches depending on the first word of eating field, instead of:
GROUP BY eating
use:
GROUP BY SUBSTRING_INDEX(`eating`, ' ', 1)
So the whole query could look like this:
SELECT i1.*
FROM info AS i1
JOIN (
SELECT SUBSTRING_INDEX(`eating`, ' ', 1) AS eating
FROM info
GROUP BY SUBSTRING_INDEX(`eating`, ' ', 1)
HAVING COUNT(DISTINCT `name`) > 1
) AS i2 ON i1.eating LIKE CONCAT(i2.eating, '%');
Demo here
I've stripped out the irrelevant parts of the problem...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(name VARCHAR(12) NOT NULL
,eating VARCHAR(12) NOT NULL
,PRIMARY KEY(name,eating)
);
INSERT INTO my_table VALUES
('aman','mango'),
('ramesh','mango'),
('aman','guava'),
('ramesh','pineapple');
SELECT DISTINCT x.*
FROM my_table x
JOIN my_table y
ON y.name <> x.name
AND y.eating = x.eating;
+--------+--------+
| name | eating |
+--------+--------+
| ramesh | mango |
| aman | mango |
+--------+--------+
Related
I'm trying to get a MySQL query to combine two tables. Both tables have a user_id and date column and the other columns are unique to each table. What I'm looking to accomplish is best explained with an image (imgur). I've tried various joins and unions and can't get the right combination. I've also tried searching stackoverflow but I'm likely not using the right terminology for what I'm looking to do.
The description of the tables in TEXT:
tablel
user_id date animals
1 9/15/2020 Lion
2 8/11/2020 Tiger
3 12/12/2020 Bear
table2
user_id date fruit
1 7/7/2020 apple
2 6/5/2020 pear
4 3/8/2020 peach
output
user_id date animals fruit
1 9/15/2020 Lion
1 7/7/2020 apple
2 8/11/2020 Tiger
2 6/5/2020 pear
3 12/12/2020 Bear
4 3/8/2020 peach
With UNION ALL you can achieve that
SELECT user_id, date, animals, fruit FROM
(
SELECT user_id, date, animals, '' as fruit
FROM table1
UNION ALL
SELECT user_id, date, '', fruit
FROM table2
) t
ORDER BY user_id, animals
You may also try FULL OUTER JOIN:
SELECT user_id, date, animals, '' as fruit
FROM table1
FULL OUTER JOIN table2
ON table1.user_id = table2.user_id AND table1.date = table2.date
-- use test;
-- drop table if exists table1;
create table table1(user_id int, `date` date, animals varchar(10));
insert into table1 values(1,'2020/09/15','Lion');
insert into table1 values(2,'2020/11/08','Tiger');
insert into table1 values(3,'2020/12/12','Bear');
-- drop table if exists table2;
create table table2(user_id int, `date` date, fruit varchar(10));
insert into table2 values(1,'2020/07/07','apple');
insert into table2 values(2,'2020/05/06','pear');
insert into table2 values(4,'2020/08/03','peach');
select
user_id,
`date`,
animals,
'' as fruit
from table1
union all
select
user_id,
`date`,
'',
fruit
from table2
order by user_id,`date`;
output:
+ ------------ + --------- + ------------ + ---------- +
| user_id | date | animals | fruit |
+ ------------ + --------- + ------------ + ---------- +
| 1 | 2020-07-07 | | apple |
| 1 | 2020-09-15 | Lion | |
| 2 | 2020-05-06 | | pear |
| 2 | 2020-11-08 | Tiger | |
| 3 | 2020-12-12 | Bear | |
| 4 | 2020-08-03 | | peach |
+ ------------ + --------- + ------------ + ---------- +
the more simple query to understand it would be :
SELECT * FROM tablel, table2 WHERE table1.user_id = table2.user_id
the second table need to have a foreign key, that have the id like the fisrt table, this query that I show you works like a INNER JOIN.
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 would like to concatenate all the item names of an order; however, if the total number of unique item names exceeds a certain number, then I want to to truncate each name before concatenating the names. Below are the conditions:
If the total number of unique item names in the order is less than 5, then use the full-length item name and concatenate the names; else if the total number of unique item names is greater than 5, then truncate each item name to 20 characters and concatenate the truncated names. For example, below is my table:
order_id | item_name | item_name_len
---------|-------------------------------------|--------------
1 | "pampers diapers ultra sensitive" | 31
1 | "cabbage salad pure organic greens" | 33
1 | "milky way" | 9
1 | "sea salt" | 8
1 | "cool waters fruit juice" | 23
| |
2 | "pure clear glass crystals" | 25
2 | "simple sugar edible paper" | 25
I want the following results:
order_id | all_item_names
---------|-----------------------------------------------------------
1 | "pampers diapers ultr ; cabbage salad pure o ; milky way ;
| sea salt ; cool waters fruit ju"
|
2 | "pure clear glass crystals ; simple sugar edible paper"
For Order #1, since there are 5 unique item names in the order, we truncate each of the item names to 20 characters and concatenate the truncated names. For Order #2, since there are only 2 unique item names in the order, we take the full-length of the name and concatenate them. (I've included the item name strlen in the table above for illustration.)
I'm trying to use a ternary condition, but it's not working.
IF( COUNT(DISTINCT item_name) < 5, item_name, SUBSTRING(item_name, 1, 20) )
See query below. I get Error code: 1111. Invalid use of group function
SELECT
w.order_id,
(SELECT GROUP_CONCAT( IF ( COUNT(DISTINCT o.item_name) < 5 ,
o.item_name, SUBSTRING(o.item_name, 1, 20) ) ) separator ' ; ' )
FROM order_items o WHERE o.order_id = w.order_id)AS all_item_names
FROM order_items w
GROUP BY order_id
You can do this with one aggregation and no join:
select oi.order_id,
(case when count(*) < 5
then group_concat(oi.item_name separator '; ')
else group_concat(left(oi.item_name, 20) separator ';')
end) as all_item_names
from order_items oi
group by oi.order_id
Group once to get the number of items and join to the table for the final group_concat:
select
o.order_id,
group_concat(
case
when counter < 5 then item_name
else left(item_name, 20)
end SEPARATOR ' ; '
) all_item_names
from order_items o inner join (
select
order_id, count(*) counter
from order_items
group by order_id
) g on g.order_id = o.order_id
group by o.order_id
See the demo
Results:
| order_id | all_item_names |
| -------- | ----------------------------------------------------------------------------------------- |
| 1 | pampers diapers ultr ; cabbage salad pure o ; milky way ; sea salt ; cool waters fruit ju |
| 2 | pure clear glass crystals ; simple sugar edible paper |
Sorry if my question sounds misleading, I'm not fully sure how to formulate it.
Consider the following tables: Fruit which has an ID and Name, Person which also has an ID and Name, and Person_has_Fruit (many to many linking table) which has a Person_ID and a Fruit_ID.
What transaction can retrieve the people which have two or more specific fruits? Basically how can I intersect the results?
Example:
Fruit table
ID | Name
-----------------
1 | Apple
2 | Pineapple
3 | Banana
4 | Lemon
Person table
ID | Name
-----------------
1 | Tom
2 | Bill
3 | John
Many to many table
PersonID | FruitID
-----------------
3 | 1
1 | 2
3 | 2
2 | 3
3 | 3
I want a query to retrieve me John when I ask for the person which has Apple, Pineapple and Banana. Any suggestions?
I've tried 'SELECT * FROM Person_has_Fruit WHERE FruitID in ('1', '2', '3')' but that is incorrect as it retrieves all the person IDs which have one of them, so basically it implies an or relationship between the values.
You are looking to perform a relational division between the some tuples of Fruit table and the Person table.
So:
Select * From Person p
Where Not Exists ( Select * from Fruit f
Where (Name = 'Apple' Or Name = 'Pinneapple' or Name = 'Banana')
And Not Exists ( Select * from Person_has_Fruit pf
Where pf.PersonId = p.ID and pf.FruitId=f.ID))
Try create a view first.
CREATE VIEW fruitowners AS
( SELECT personfruit.personID, fruittable.id, persontable.person, fruittable.fruit
FROM persontable, fruittable, personfruit
WHERE personfruit.personID=persontable.id AND personfruit.fruitID=fruittable.id )
Then:
SELECT fruit FROM fruitowners
WHERE person='John'
returns all the fruit types John owns
And:
SELECT person FROM fruitowners
WHERE fruit='Banana'
returns all the banana owners.
And:
SELECT COUNT(*) FROM fruitowners WHERE person='John'
returns the number of fruits John owns
And:
SELECT COUNT('fruit') FROM fruitowners WHERE person='John' and fruit='Banana'
returns how many bananas John owns
For example I have a table with three fields:
id (int)
name (varchar)
company (int)
Let's say that I have the following data (example only)
id --- name --- company
---------------------------------------
1 --- John Baker --- 1
2 --- Ann Johnson --- 1
3 --- John Wu --- 1
4 --- Mike Johns --- 2
5 --- John John --- 2
6 --- Johnny Boy --- 2
I would like perform a search on name, and return the data staggered by company. So if I perform a search on LIKE '%John%' , I wish to return the data in a way where it is sorted by company like: 1, 2, 1, 2, 1, 2 whilst maintaining as much relevancy in return order to the original search term as possible.
I have no idea how to return the data in this staggered way, and I have thought about it for hours. If somebody can please help me I'd love to hear their ideas!
This would be rather easy if we could use SQL standard functions to ROW_NUMBER each name PARTITIONed BY company. (ROW_NUMBER gives us a "naive ranking" or simple numbering, with no ties and no gaps.) This is essentially #zebediah49's proposal in his comment. MySQL, sadly, cannot today do this.
#GordonLindoff's answer simulates this functionality in MySQL with a self-join technique. Here's another way to do the same.
First we group every person by company and then globally naively rank them, using a user variable. So, the three people in company A become #1, #2, and #3, and the two people in company B become #4 and #5, and so on:
company | name == ROW_NUMBER()d after ==> company | name | rank
--------+-------- == GROUP BY `company` ==> --------+---------+------
A | Alice A | Alice | 1
B | Bob A | Charlie | 2
A | Charlie A | Deborah | 3
A | Deborah B | Bob | 4
B | Erwin B | Erwin | 5
The user variable technique to simulate ROW_NUMBER in MySQL is easy to search for, but here's a compact demonstration from another SO answer.
Now if we MOD a global naive rank by the number of people within a company, we get a "partitioned rank", a relative rank within the company:
company | name | rank | npeople | rank % npeople
--------+----------+------+---------+----------------
A | Alice | 1 | 3 | 1
A | Charlie | 2 | 3 | 2
A | Deborah | 3 | 3 | 0
B | Bob | 4 | 2 | 0
B | Erwin | 5 | 2 | 1
Putting it all together, JOINing against a query to count the number of people in each company, we get:
SELECT id, name, ranked.company
FROM ( SELECT tbl.id, tbl.name, tbl.company, (#rn := #rn + 1) AS rn
FROM tbl
JOIN (SELECT #rn := 0) vars
WHERE tbl.name LIKE '%John%'
ORDER BY company) ranked
JOIN (SELECT company, COUNT(id) AS npeople FROM tbl GROUP BY company) companies
ON ranked.company = companies.company
ORDER BY rn MOD companies.npeople, company
If you want it sorted by company:
select *
from t
where . . .
order by company, id;
If you want it interleaved, then a counter within a company helps. Here is one way:
select t.*
from (select *,
(select count(*) from t t2 where <where clause on t2 here> and t2.comapny = t.company and t2.id < t.id) as seqnum
from t
where . . .
) t
order by seqnum, company
One possible solution:
select *
from yourTable
where ...
order by ((company*1000) + id);
Add as much zeros as you need. At least, you'll need as much zeros as this number:
select pow(10,length(max(company))) from yourTable;
The ordering may be quite slow if you pull a lot of records in this query, so I suggest you use an optimal where condition.
Not the most elegant solution, but it may work.