I have 2 tables, animal and people, I am making a query using UNION to get a combined list of both tables, but I want every 4 animals I look 1 person, that is:
Results:
*animal 1
animal 2
animal 3
animal 4*
**person 1**
*animal 5
animal 6
animal 7
animal 8*
**person 2**
etc...
Is there any way to do it?
Please help me!
DEMO: using rextester
Using user variables you can often simulate analytics in enterprise databases (though not nearly as efficient)
We generate derived table (UnionSeq) to generate the needed sequencing and then add our own formula to multiply the generated row_number for persons to be 4 * greater so it will fit in after the 4th animal and use column aliased seq to determine that animals come before people in the order. Then we select from the derived table to apply the needed ordering.
SELECT Name
FROM (SELECT ID, Name, (#p:=#P+1)*4 Row_num, 'b' as Seq
FROM person
CROSS JOIN (SELECT #p:=0) a
UNION ALL
SELECT ID, Name, #a:=#a+1, 'a' as seq
FROM animal
CROSS JOIN (SELECT #a:=0) b) UnionSeq
ORDER BY Row_num, Seq
Giving us:
+----+----------+
| | Name |
+----+----------+
| 1 | Animal 1 |
| 2 | Animal 2 |
| 3 | Animal 3 |
| 4 | Animal 4 |
| 5 | Person 1 |
| 6 | Animal 5 |
| 7 | Animal 6 |
| 8 | Animal 7 |
| 9 | Animal 8 |
| 10 | Person 2 |
| 11 | Animal 9 |
| 12 | Person 3 |
+----+----------+
Your sample data doesn't show what to do if there are disproportionate numbers of people to animals; so in my demo I just let each table show all data based on a pattern irrespective if the 4x1 pattern can't be maintained. In this example you can see Animal 9 is followed by person 3 even though there aren't 4 animals. and if there was a person 4 it would follow person 3 as there would be no more animals.
It's not magic; it's math and general SQL processes and order of operations.
Related
This question already has an answer here:
Mysql group by two columns and pick the maximum value of third column
(1 answer)
Closed 2 years ago.
I've been taking too long trying to solve this, I need to filter this table:
+----+-------+-------+
| id | jobID |stageID|
+----+-------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 2 |
| 4 | 1 | 1 |
| 5 | 2 | 2 |
| 6 | 2 | 1 |
| 7 | 2 | 1 |
| 8 | 2 | 2 |
+----+-------+-------+
You see every job has many rows with different stages, I need to get the last row of every stage of every job.
For example, look at job 1. It has 4 rows, each one with a given stage. I'd need to get the last entry of a stage for that job, which means, rows 3 and 4.
So for the full table I need to get rows No. 3, 4, 7 and 8, like this
+----+-------+-------+
| id | jobID |stageID|
+----+-------+-------+
| 3 | 1 | 2 |
| 4 | 1 | 1 |
| 7 | 2 | 1 |
| 8 | 2 | 2 |
+----+-------+-------+
I think I'll go nuts. I try with GROUP_BY but it groups the stages without taking in count the jobs.
Can you help me?
This is simply:
select max(id) as id, jobID, stageID
from yourtable
group by jobID, stageID
If you need additional information selected, use that as a subselect:
select yourtable.id, yourtable.jobID, yourtable.stageID, yourtable.other
from (
select max(id) as id
from yourtable
group by jobID, stageID
) max_job_stage_ids
join yourtable using (id)
or use IN (I find this less helpful in visualizing the query plan, but some people prefer it):
select id, jobID, stageID, other
from yourtable
where id in (select max(id) from yourtable group by jobID, stageID)
The title is a bit messy, but here's an example
suppose we have table:
| name | room |
=================
| John | 4 |
| John | 6 |
| John | 9 |
| Smith | 4 |
| Smith | 6 |
| Brian | 4 |
| Brian | 6 |
| Brian | 9 |
I want to select John and Brian because they both have exactly rooms 4, 6 and 9, but not Smith, since he doesn't have the room 9. (If we had another person who ONLY has room 4 and 6, then it'd select that other person as well as Smith).
I know I need to do some kind of correlated query, but I'm not sure how to actually get it to do something like
for a check for b
If you want groups of names that share the exact same rooms, I would recommend group_concat():
select rooms, group_concat(name) as names
from (select name, group_concat(room order by room) as rooms
from t
group by name
) n
group by rooms;
If you want only combinations with more than one name, then add having count(*) > 1 to the outer select.
I have three tables, which are below with related details
1. Primary words
+----+---------+
| id | word |
+----+---------+
| 1 | Machine |
+----+---------+
| 2 | phone |
+----+---------+
2. Alternative words
+----+------------+-----------+
| id | primary_id | word |
+----+------------+-----------+
| 1 | 1 | system |
+----+------------+-----------+
| 2 | 1 | feature |
+----+------------+-----------+
| 3 | 2 | telephone |
+----+------------+-----------+
3. product table
+----+------------------+
| id | name |
+----+------------------+
| 1 | mobile system |
+----+------------------+
| 2 | computer machine |
+----+------------------+
| 3 | wired telephone |
+----+------------------+
Now twist is that whenever user search with "machine" in product table then display results of product with table name have "machine" or "system" or "feature" and if search with "system" or "feature" then also display results of "machine" or "system" or "feature".or vice vera.
Would you please suggest me how can solve this one?
If I understand correctly what you are asking...
SQL
SELECT *
FROM Product P
WHERE EXISTS(SELECT fw.Word --(6) select all products that exist in this query
FROM (SELECT pw.Word --(1) select all Primary words matching input
FROM PrimaryWords pw
WHERE pw.Word = 'machine'
UNION --(3) union the results from both selects
SELECT aw.Word --(2) select all Alternative words that match input or have its primary matching it
FROM PrimaryWords pw INNER JOIN AlternativeWords aw
ON pw.Id = aw.PrimaryId
WHERE pw.Word = 'machine'
OR aw.Word = 'machine') as fw --(4) alias the result
WHERE p.Name LIKE '%' || fw.Word || '%'); -- (5) filter products that match the valid words
you can read the comments ordered by the numbering in ().
First of all you need to take those two table data inti one and then give condition.
Select word from(
SELECT id,word FROM PrimaryWords
Union all
Select primaryid,word from AlternativeWords a
) where id in ( select id from primarywords where word='yoursearchketword'
Union
Select primaryid from AlternativeWords where word='yoursearchketword')
Updated Answer as per your product table.
Now you need to cross join the product table, because there is no relationship between them.
One more thing is you have to use like operator here to compare you desired result with prouct table's name column. Here I have given small idea How to accomplish that, but you can easily improve the same.
Select a.word,b.name from
(Select word from(
SELECT id,word FROM PrimaryWords
Union all
Select primaryid,word from AlternativeWords a
) where id in ( select id from primarywords where word='yoursearchketword'
Union
Select primaryid from AlternativeWords where word='yoursearchketword')) a, product b
Where a.word LIKE CONCAT('%',name, '%');
I suggest to put it in one table like this:
id | primary_id | word
1 | 1 | machine
2 | 2 | phone
3 | 1 | system
4 | 1 | feature
5 | 2 | telephone
And the query will be like this, lets take machine word as an example:
Select word from MyTable where primary_id in
(select primary_id from MyTable where word = "machine")
The output: machine, system, feature
Update
In case you have more columns, for example to show how much related are these words, you can add one more table to map between words, like the following:
id | w1_id | w2_id | relation
1 | 1 | 3 | 80
2 | 2 | 5 | 90
3 | 1 | 4 | 60
4 | 3 | 4 | 60
And the words table will list only the words like:
id| word
1 | machine
2 | phone
3 | system
4 | feature
5 | telephone
In this thread you will find a long discussion talking about way you have to design the layout of your schema as well as hints in how retrieve your data.
I have products with different rankings. The products may be members of a supergroup (like Cream).
product_id | supergroup | rank | other_info
1 | Cream | 3 | Eric
2 | Zep | 1 | Jimmy
3 | Zep | 4 | Jon Paul
4 | Cream | 3 | Jack
5 | Cream | 4 | Ginger
6 | Who | 4 | Roger
7 | Who | 5 | John
8 | Who | 3 | Pete
I want to get the max product rank from each group, along with other info for that product id. Ranks are not meant for intragroup ranks. They are ranks that work across all products in the system. So more than one product may have the same rank, even in the same group.
EDIT: fixed "other_info". I had some gibberish there. Also added a row. Results should be from highest rank to lowest. But they also should only include the highest ranking product_id from each supergroup, along with matching other_info.
product_id | supergroup | rank | other_info
2 | Zep | 1 | Jimmy
8 | Who | 3 | Pete
1 | Cream | 3 | Eric
Can I do that with a simple query? The existing system's query already involves a GROUP BY statement on the supergroup, and no aggregators in the SELECT. That results in a random, but coherent row from within the group. What is the simplest way to modify the query to get a complete row, but always of the highest-ranked member of each super group.
If there is no way, what about this: Is this possible without GROUP BY?
SELECT t.*
FROM your_table t
JOIN (
SELECT MIN(product_id) as product_id #if there are multiple products with the same (min) rank in the same supergroup - get the one with lowest product_id
FROM your_table tt
JOIN (
SELECT supergroup, MIN(rank) as min_rank
FROM your_table
GROUP BY supergroup
) mr ON mr.supergroup = tt.supergroup AND mr.min_rank = tt.rank
GROUP BY tt.supergroup, tt.rank
) as mid ON mid.id.product_id = t.product_id
ORDER BY whatever_you_need_to
You need an index on (supergroup,rank) for this to run efficiently.
I can't get on the right track with this, any help would be appreciated
I have one table
+---+----------+---------+-----------+
|id | match_id | team_id | player_id |
+---+----------+---------+-----------+
| 1 | 9 | 10 | 5 |
| 2 | 9 | 10 | 7 |
| 3 | 9 | 10 | 9 |
| 4 | 9 | 11 | 12 |
| 5 | 9 | 11 | 15 |
| 6 | 9 | 11 | 18 |
+---+----------+---------+-----------+
I want to select these with a where on the match_id and both team id's so the output will be
+---------+-------+------+---------+---------+
| MATCHID | TEAMA | TEAMB| PLAYERA | PLAYERB |
+---------+-------+------+---------+---------+
| 9 | 10 | 11 | 5 | 12 |
| 9 | 10 | 11 | 7 | 15 |
| 9 | 10 | 11 | 9 | 18 |
+---------+-------+------+---------+---------+
It's probably very simple, but i'm stuck..
thanks in advance
p.s. seemed to forgot a column on my first post, sorry
I think you should redesign your table though, maybe the format that you want as output should be your table design.
With your design, it's possible to have three or more teams playing against each other...
So. I gave this another try (coming from Oracle myself, I really miss ROWNUM here).
The following query should give you the result you want to have, but I'm not sure if you should really do that in pure SQL. Maybe you could just combine the teams in your client?
SELECT m1.match_id, m1.team_id, m2.team_id, m1.player_id, m2.player_id
FROM (
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m1b
WHERE m1b.match_id = m1a.match_id
AND m1b.team_id = m1a.team_id
AND m1b.player_id < m1a.player_id) rank
FROM matches m1a
WHERE m1a.team_id = (SELECT MIN(team_id) -- first team
FROM matches
WHERE match_id = m1a.match_id)
) m1,
(
SELECT match_id, team_id, player_id,
-- get ranking
( SELECT 1 + count(*)
FROM matches m2b
WHERE m2b.match_id = m2a.match_id
AND m2b.team_id = m2a.team_id
AND m2b.player_id < m2a.player_id) rank
FROM matches m2a
WHERE m2a.team_id = (SELECT MAX(team_id) -- second team
FROM matches
WHERE match_id = m2a.match_id)
) m2
WHERE m1.match_id = m2.match_id
AND m1.rank = m2.rank
What I do here is:
Select all ROWs from the teams with lower team_id per match and give them a ranking (1 to 3 per match)
Select all ROWs from the teams with higher team_id per match and give them a ranking (1 to 3 per match)
Combine those two queries in one result, where the match_id and the ranking match
match is a reserve word in mysql. table name used here is matchs
select match_id, sum(if(id=1, team_id,0))team_A, sum(if(id=2,team_id,0)) team_b
from matchs
group by match_id;
+----------+--------+--------+
| match_id | team_A | team_b |
+----------+--------+--------+
| 5 | 9 | 10 |
+----------+--------+--------+
1 row in set (0.00 sec)
I'm not sure if the previous answers will give you what you're looking for, at least I took your question to mean something else - perhaps you could clarify the purpose of the table and the query. If the table associates teams with matches and you want a query to show you all the teams associated with one match, then your query should be
select team_id as teams from table where match_id = id_here
which would give you back (for id_here being 5)
teams
-----
9
10
Take a look at the url below, It is exactly what you want but is in t-sql. It can merge any number of rows.
Converting fields into columns