I have 3 tables: sports, venues and instructors, they all have an id and a name. Instead of having 3 separate SELECT * FROM table I want to fetch the results with a single query so that the result is something like:
+----------+------------+----------+------------+---------------+-----------------+
| sport_id | sport_name | venue_id | venue_name | instructor_id | instructor_name |
+----------+------------+----------+------------+---------------+-----------------+
| 1 | Sport1 | 1 | Venue1 | 1 | Instructor1 |
| 2 | Sport2 | 2 | Venue2 | 2 | Instructor2 |
| 3 | Sport3 | | | 3 | Instructor3 |
| 4 | Sport4 | | | | |
+----------+------------+----------+------------+---------------+-----------------+
I tried
SELECT * FROM sports, venues, instructors
However there are at ton of repetitions.
EDIT: The 3 tables are not related to each other in any way.
Although I see limited use for getting all the values in one query, you could alway use UNION ALL to get all the values;
SELECT sport_id id, sport_name name, 'sport' type FROM sports
UNION ALL
SELECT venue_id id, venue_name name, 'venue' type FROM venues
UNION ALL
SELECT instructor_id id, instructor_name name, 'instructor' type FROM instructors
This will give output in the format;
id name type
-------------------------------
1 sport1 sport
2 sport2 sport
3 sport3 sport
4 sport4 sport
1 venue1 venue
2 venue2 venue
1 instructor1 instructor
2 instructor2 instructor
3 instructor3 instructor
Related
I have two independent tables: 'Clients' and 'Country'.
Country Table:
IdCountry Country
1 SPAIN
2 PORTUGAL
Clients Table
IdClient Entity IdCountry
1 Adam Alves 2
2 Peter Smith 2
3 David Ramos 1
4 Rafael Castro 1
I would like to add a new client into 'Clients' table but using the information from 'Country' table like this:
INSERT INTO Clients(IdClient, Entity, Country)
SELECT max(IdClient) + 1, '--New--' FROM Clients,
SELECT IdCountry FROM Country WHERE Country = 'SPAIN'
I would like to have this INPUT:
IdClient Entity IdCountry
5 --New-- 1
But if I run this query, it doesn't work. Could anybody help me, please?
COMMENTS: I prefer don't use autoincrement option.
Thank you very much.
Wardiam
You can do it like this:
INSERT INTO Clients(IdClient, Entity, Country)
SELECT
(SELECT MAX(IdClient) + 1 FROM Clients),
'--New--',
(SELECT IdCountry FROM Country WHERE Country = 'SPAIN')
See the demo.
Results:
| IdClient | Entity | Country |
| -------- | ------------- | ------- |
| 1 | Adam Alves | 2 |
| 2 | Peter Smith | 2 |
| 3 | David Ramos | 1 |
| 4 | Rafael Castro | 1 |
| 5 | --New-- | 1 |
I have two tables A and B table:
Table - A - represents basic information of persons
emp_id | email | name
----------------------------------------
1 | abc#gmail.com | john
2 | dbc#gmail.com | john1
3 | cbc#gmail.com | john2
4 | xbc#gmail.com | john3
5 | xac#gmail.com | john4
Table - B represents the locations handled by persons
john is handling Region and Zone
john1 is handling Area and Territory and so on...
Sequence of locationType is as follows : Region->Zone->Area->Territory
Regions is having higher priority then comes zone and so on..
id | emp_id | locationType
--------------------
1 | 1 | Region
2 | 2 | Area
3 | 3 | Area
4 | 4 | Territory
5 | 1 | Zone
6 | 2 | Territory
7 | 5 | Zone
8 | 5 | Area
I want to fetch those persons who are handling the higher locationType.
Suppose john is handling Region and zone so i want to display Region as Region is of higher priority and similarly john1 is handling Territory and Area so i want to display only Area as because Area is of higher priority
My Desired Output:
id | emp_id | name | locationType
----------------------------------------
1 | 1 | john | Region
5 | 5 | john4 | Zone
3 | 3 | john1 | Area
4 | 4 | john2 | Area
4 | 4 | john3 | Territory
What I am getting
id | emp_id | name | locationType
----------------------------------------
1 | 1 | john | Region
1 | 1 | john | Zone
5 | 5 | john4 | Zone
5 | 5 | john4 | Area
2 | 2 | john1 | Area
3 | 3 | john2 | Area
4 | 4 | john3 | Territory
4 | 4 | john3 | Territory
You can use field() to turn the locations into numbers. What you want is the minimum location based on this ordering.
You can obtain this information per employee using a correlated subquery:
select b.*
from b
where field(b.locationType, 'Region', 'Zone', 'Area', 'Territory') =
(select min(field(b2.locationType, 'Region', 'Zone', 'Area', 'Territory'))
from b b2
where b2.emp_id = b.emp_id
);
Adding the extra columns from a is just a matter of joining in the table.
use case when in order clause
order by (case locationType when 'Region' then 1
when 'Zone' then 2
when 'Area' then 3
when 'Territory' then 4
else 5 end )
To Resolve the Issue Pemanently just Follow the following steps. It will help you in data normalization also.
1 Create A new table that has LocaitonType name and id and Insert your location type as the order you want.
CREATE TABLE [dbo].[Table_C](
[LocationType_Id] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](50) NULL )
Insert Into [Table_C] (name) values('Region')
Insert Into [Table_C] (name) values('Zone')
Insert Into [Table_C] (name) values('Area')
Insert Into [Table_C] (name) values('Territory')
2.Alter your table b LocationType column Data type to int.
Alter Table Table_B
Alter column locationType int not null
Now Insert id from Table_c to Table_B Locationtype Column.
and use the below query to get the desired output.
Select Table_B.id,Table_A.emp_id,Table_A.name,Table_C.name as locationType from Table_B inner join Table_A on Table_A.emp_id=Table_B.emp_id
inner join Table_C on Table_C.LocationType_Id=Table_B.locationType
order by Table_C.LocationType_Id
I have a table of students with temporary test values like this:
Table students
+----+-------------+-------+-----------+
| id | section_id | age | name |
+----+-------------+-------+-----------+
| 1 | 1 | 18 | Justin |
+----+-------------+-------+-----------+
| 2 | 2 | 14 | Jillian |
+----+-------------+-------+-----------+
| 3 | 2 | 16 | Cherry |
+----+-------------+-------+-----------+
| 4 | 3 | 19 | Ronald |
+----+-------------+-------+-----------+
| 5 | 3 | 21 | Marie |
+----+-------------+-------+-----------+
| 6 | 3 | 21 | Arthur |
+----+-------------+-------+-----------+
I want to query the table such that I want to get all the maximum ages of each section. However, if two students have the same age, the table produced will return the student with smallest id.
Return:
+----+------------+-----+--------+
| id | section_id | age | name |
+----+------------+-----+--------+
| 1 | 1 | 18 | Justin |
+----+------------+-----+--------+
| 3 | 2 | 16 | Cherry |
+----+------------+-----+--------+
| 5 | 3 | 21 | Marie |
+----+------------+-----+--------+
I tried this query:
SELECT ANY_VALUE(id), ANY_VALUE(section_id), MAX(age), ANY_VALUE(name) FROM
(SELECT id, section_id, age, name FROM students ORDER BY id) as X
GROUP BY section_id
Unfortunately, there are instances that id does not match the age and name.
I have on my end:
sql_mode = only_full_group_by
and I don't have a privilege to edit that, hence the any_value function but I have no idea how to use it.
This will do what you want.
It starts by finding the maximum age per section (including duplicates).
Then it joins those results with the minimum id per section (to eliminate duplicates).
And finally, select all fields for the matching id and section combinations.
SELECT s3.*
FROM students s3
INNER JOIN (
SELECT MIN(s2.id) AS id, s2.section_id
FROM students s2
INNER JOIN (
SELECT s1.section_id, MAX(s1.age) AS age
FROM students s1
GROUP BY s1.section_id
) s1 USING (section_id, age)
GROUP BY s2.section_id
) s2 USING (id, section_id);
Working SQL fiddle: https://www.db-fiddle.com/f/aezgAYM6A5KnXykceB7At1/0
I would simply use a correlated subquery:
select s.*
from students s
where s.id = (select s2.id
from students s2
where s2.section_id = s.section_id
order by s2.age desc, s2.id asc
limit 1
);
This is pretty much the simplest way to express the logic. And with an index on students(section, age, id), it should be the most performant as well.
It's the 3rd day I'm trying to write a MySQL query. Did lots of search, but it still doesn't work as expected. I'll try to simplify tables as much as possible
System has tkr_restaurants table:
restaurant_id | restaurant_name
1 | AA
2 | BB
3 | CC
Each restaurant has a division assigned (tkr_divisions table):
division_id | restaurant_id | division_name
1 | 1 | AA-1
2 | 1 | AA-2
3 | 2 | BB-1
Then there are meals in tkr_meals_to_restaurants_divisions table, where each meal can be assigned (mapped) to whole restaurant(s) and/or specific division(s). If meal is mapped to restaurant, all restaurant's divisions should see it. If meal is mapped to division(s), only specific division(s) should see it.
meal_id | mapped_restaurant_id | mapped_division_id
1 | 1 | NULL
2 | NULL | 1
3 | NULL | 2
I need to display a list of restaurants and number of meals mapped to it depending on user permissions.
Example 1: if user has permissions to access whole restaurant_id 1 and restaurant_3 (and no specific divisions), then list should be:
AA | 3
CC | 0
(because user can access meals mapped to restaurant 1 + all its division, and restaurant 3 + all its divisions (even if restaurant 3 has no divisions/meals mapped))
Example 2: if user has permissions to access only division_id 1, then list should be:
AA | 1
(because user can only access meals mapped to division 1).
The closest query I could get is:
Example 1:
SELECT *,
(SELECT COUNT(DISTINCT meal_id)
FROM
tkr_meals_to_restaurants_divisions
WHERE
tkr_meals_to_restaurants_divisions.mapped_restaurant_id=tkr_restaurants.restaurant_id
OR tkr_meals_to_restaurants_divisions.mapped_division_id=tkr_divisions.division_id)AS total_meals
FROM
tkr_restaurants
LEFT JOIN
tkr_divisions
ON tkr_restaurants.restaurant_id=tkr_divisions.restaurant_id
WHERE
tkr_restaurants.restaurant_id IN (1, 3)
OR tkr_restaurants.restaurant_id IN (
SELECT restaurant_id
FROM tkr_divisions
WHERE division_id IN (NULL)
)
GROUP BY
tkr_restaurants.restaurant_id
ORDER BY
tkr_restaurants.restaurant_name
However, result was:
AA | 2
CC | 0
I believe I'm greatly over-complicating this query, but all the simpler queries I wrote produced even more inaccurate results.
What about this query:
SELECT
FROM tkr_restaurants AS a
JOIN tkr_divisions AS b
ON a.restaurant_id = b.restaurant_id
LEFT OUTER JOIN tkr_meals_to_restaurants_divisions AS c
ON (c.mapped_restaurant_id = a.restaurant_id OR c.mapped_division_id = b.division_id)
As a Base four your further work. It combine all information into one table. If you add e.g. this:
WHERE a.restaurant_id IN (1, 3)
the result will be
| restaurant_id | restaurant_name | division_id | restaurant_id | division_name | meal_id | mapped_restaurant_id | mapped_division_id |
|---------------|-----------------|-------------|---------------|---------------|---------|----------------------|--------------------|
| 1 | AA | 1 | 1 | AA-1 | 1 | 1 | (null) |
| 1 | AA | 2 | 1 | AA-2 | 1 | 1 | (null) |
| 1 | AA | 1 | 1 | AA-1 | 2 | (null) | 1 |
| 1 | AA | 2 | 1 | AA-2 | 3 | (null) | 2 |
just count the distinct meal ids with COUNT(DISTINCT c.meal_id) and take the restaurant name to get AA: 3 for your example 2
I used a sqlfiddle: http://sqlfiddle.com/#!9/fa2b78/18/0
[EDIT]
Change JOIN tkr_divisions AS b to LEFT OUTER JOIN tkr_divisions AS b
Change SELECT * to SELECT a.restaurant_name, COUNT(DISTINCT c.meal_id)
Add a GROUP BY a.restaurant_name at the end.
Update the SQL Fiddle (new link)
I have a table "player" as follow
where:
ID is primary key.
date = date they play (just for 1 month, so could from 1 to 31)
Name = name of the players
Sport = sport they play and there can be many sports in the list; but i only focus on the one who play "football" and play more than 2 games in one day
This is the table "player".
+----+------------+-------+-------------+
| ID | Date | Name | Sport |
+----+------------+-------+-------------+
| 1 | 1 | A | football |
| 2 | 1 | A | soccer |
| 3 | 3 | A | tennis |
| 4 | 2 | B | tennis |
| 5 | 2 | B | football |
| 6 | 1 | C | basketball |
| 7 | 1 | C | tennis |
| 8 | 1 | C | fishing |
| 9 | 4 | D | football |
+----+------------+-------+-------------+
I want to find list of the people (name and sport) who DO NOT:
practice "football" + other sport(s) in one day.
note: if someone who play "football" + other game(s) in one day, we remove him from the list for that day. only remove him for that particular day.
So the result should be like this,
+----+------+------+-----------+
| ID | Date | Name | Sport |
+----+------+------+-----------+
| 3 | 3 | A | tennis |
| 6 | 1 | C | basketball|
| 7 | 1 | C | tennis |
| 8 | 1 | C | fishing |
| 9 | 4 | D | football |
+----+------+------+-----------+
This is the follow up problem listed
mysql: find rows with repeated values plus condition
thank you for helping !
You should be looking for this:
Here, we are omitting the key record values (date + name) those match in an intersection of key record values (date + name) who played football and key record values (date + name) who did not play football
SELECT
p1.*
FROM
player p1
LEFT JOIN
(SELECT
pnfb.*
FROM
(SELECT
date, name
FROM
player
WHERE
sport <> 'football') pnfb
JOIN (SELECT
date, name
FROM
player
WHERE
sport = 'football') pfb ON (pnfb.date = pfb.date
AND pnfb.name = pfb.name)) p2 ON (p1.date = p2.date AND p1.name = p2.name)
WHERE
p2.date IS NULL;
If I've understood correctly, you want to obtain the dates and names of players who on that date either played only one sport or did not play football:
SELECT Date, Name
FROM player
GROUP BY Date, Name
HAVING COUNT(DISTINCT Sport) = 1
OR NOT SUM(Sport='football')
See it on sqlfiddle.
If you want to see which sports they did play and/or obtain the ID of the relevant records, you can join the above back to your player table:
SELECT * FROM player NATURAL JOIN (
SELECT Date, Name
FROM player
GROUP BY Date, Name
HAVING COUNT(DISTINCT Sport) = 1
OR NOT SUM(Sport='football')
) t
See it on sqlfiddle.