mysql subquery runs indefinitely - mysql

I have two tables: I am doing a join and wish to return a query with multiple codenames listed for each GenEx prescription brand. However it looks like the way im doing the join causes it to timeout.
Drugs:
ID | GenEx | CodeName | Desc
----------------------------
1 | Cipro | Dolvo |
2 | Ludavil | Ymir |
3 | Cipro | Alpha |
Medicine:
ID | GenEx | Price |
----------------------------
1 | Cipro | 4.99 |
2 | Ludavil | 12.99 |
3 | Benazol | 5.00 |
I wish to return:
1. GenEx->Cipro, CodeName=>Dolvo,Alpha, Price->4.99
2. GenEx->Ludavil, CodeName=>Ymir, Price->12.99
myquery which never completes:
SELECT GenEx, Price
GROUP_CONCAT(CodeName) as CodeName
FROM (`Drugs` d)
JOIN `Medicine` m ON `m`.`GenEx` = `d`.`GenEx`
WHERE GenEx
IN (
SELECT DISTINCT GenEx
FROM Drugs
WHERE codeName IN ('Alpha'))
)
GROUP BY `GenEx`;

Now updated the aswer as per the last update in the question.
Try this code:
SELECT d.`GenEx`, d.`CodeName`, d.`Price`,
GROUP_CONCAT(d.`CodeName`) as CodeName
FROM Drugs d
JOIN Medicine m
ON m.`GenEx` = d.`GenEx`
AND d.`GenEx`
IN (
SELECT DISTINCT `GenEx`
FROM drugs
WHERE codeName IN ('Alpha'))
)
GROUP BY d.`GenEx`;
And let me know what you get now.

Related

Group by one field and display multiple fields (MySQL)

So i have these three tables :
Booking :
+----+---------+--------+---------------+-------------+
| id | idRoom | idUser | startDateTime | endDateTime |
+----+---------+--------+---------------+-------------+
| 4 | 3 | 1 | 07/06/2020 | 07/07/2020 |
| 5 | 3 | 2 | 07/06/2021 | 07/06/2021 |
+----+---------+--------+---------------+-------------+
Room :
+----+--------------+
| id | description |
+----+--------------+
| 3 | Room 1 |
+----+--------------+
User :
+----+----------+
| id | userName |
+----+----------+
| 1 | User 1 |
| 2 | User 2 |
+----+----------+
And want to select all the bookings (listed in table one) while displaying the User and the Room fields infos and group by the Room object.
I am using the JOIN clause along with the GROUP BY clause as follows :
select distinct r, b, u
from Booking b
join Room r on b.idRoom=r.id
join User u on b.idUser=u.id
where r.id=3
group by r, b, u
order by r
But it is not rendering the desired result.
Anyone suggests a working SQL query ?
EDIT (Desired Result ) :
+-------+--------+-----------+
| Rooms | Users | Bookings |
+-------+--------+-----------+
| 3 | 1 | 4 |
| | 2 | 5 |
+-------+--------+-----------+
As you wants to group by your query output by room, you can start your query from the room table. But not sure how you can get the Json formatted output. You can achieve the following output and rest part you should manage in the frontend.
Possible output-
Rooms Users Bookings
3 1 4
3 2 5
Query for the above output -
SELECT R.id AS Rooms,
B.idUser AS Users,
B.ID AS Bookings
FROM Room R
INNER JOIN Booking B ON R.Id = B.idRoom
For more details of a User, you can join the User table Now.

MYSQL selecting new column based on multiple joins

I'm still working through some kinks with MySQL so any help will be appreciated.
I have 3 tables -- equipment, states, zones.
equipment:
+---------------+------+------------+
| current_state | id | ...columns |
+---------------+------+------------+
states:
+----------+-------------+
| state | zone_id |
+----------+-------------+
zones:
+-----+------+
| id | zone |
+-----+------+
In equipment, there is one current_state per row.
In states, there is one zone_id per row.
In zones, there is one zone per row.
I would like to JOIN the three tables as a subquery select statement (not even sure if that's a thing) and have the output return as 1 alias'd column among the other columns I'm selecting
+--------------+-------------+
| current_zone | ....columns |
+--------------+-------------+
A sample expected output is:
+------------+-------------+--------+------------------+--------------+---------+
| c_id | g_id | e_id | equipment_type | impressionId | email |
+------------+-------------+--------+------------------+--------------+---------+
| 1234 | ABC1234 | 0001 | VEST | 2032 |ab#yc.com|
| 1234 | 1234ABC | 0001 | SHIRT | 4372 |ab#yc.com|
| 1234 | DCBA123 | 0001 | CAN | 4372 |ab#yc.com|
| 1234 | DCBA321 | 0001 | JACKET | ab#yc.com |ab#yw.com|
| 4567 | abc321d | 0002 | SHIRT | 2032 |db#yw.com|
| 4567 | cba123d | 0002 | CAN | 4372 |db#yw.com|
| 4567 | def4rg4 | 0002 | JEANS | 3210 |db#yw.com|
+------------+-------------+--------+------------------+--------------+---------+
The current query has multiple joins already referring to the zones and states table in order to determine a different value:
SELECT equipment.*,
...
FROM equipment
LEFT JOIN c on equipment.c_id = c.id
LEFT JOIN g on equipment.g_id = g.id
LEFT JOIN states on g.state = states.state
LEFT JOIN zones on zones.id = states.zone_id
Essentially, what I want to do is create a subquery in order to create a new column based on the results of the three joins, something like this:
SELECT equipment.*,
(SELECT
equipment.current_state
FROM equipment
LEFT JOIN equipment.current_state = states.state
LEFT JOIN zones.id = states.zone_id
) as current_zone,
...
This is even possible? Am I trying to select a new column in the wrong place?
Thanks to #TheImpaler I was able to clear up my Scalar Subquery. In my eyes, I thought I had to create another join based on the properties I wanted when in reality all I had to do was create a conditional scalar subquery:
SELECT equipment.*,
(SELECT zones.zone
FROM zones
WHERE equipment.current_state = states.state
AND zones.id = states.zone_id
) as current_zone,
...

SQL Query for selecting multiple rows but highest value for each PK

I know that the title sounds horrible but I have no idea how to summarize it better. I'm pretty sure that somebody had the same problem before but I couldn't find anything. RDBMS: MySQL.
Problem:
I have the following (simplified) table:
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.01.2015 | 1 |
| A | 01.02.2015 | 3 |
| A | 01.03.2015 | 4 |
| B | 01.01.2015 | 3 |
| B | 01.02.2015 | 4 |
| B | 01.03.2015 | 5 |
| C | 01.01.2015 | 1 |
| C | 01.02.2015 | 2 |
| C | 01.03.2015 | 3 |
+------+------------+---------------------------------+
There is no unique constraint or PK defined.
The table represents a highscore of a game. Every day the score of all players are inserted with values that are: name, points, now(),...
The data represent a snapshot of the score of each player at a specific time.
I want the most recent entry for each user only but only for the highest X players. So the result should look like
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.03.2015 | 4 |
| B | 01.03.2015 | 5 |
+------+------------+---------------------------------+
C doesn't appear since he's not in the top 2 (by score)
A appears with the most recent row (by date)
B appears, like A, with the most recent row (by date) and because he is in the top 2
I hope it becomes clear what I mean.
Thanks in advance!
I understand that what you need is to first select the X players who've gotten the highest score and then get their latest performance. In this case, you should do this:
SELECT *
FROM tablename t
JOIN
(
SELECT t.name, max(t.date) as max_date
FROM tablename t
JOIN
(
SELECT name
FROM
(
SELECT name, max(score) as max_score
FROM table_name
GROUP BY name
) all_highscores
ORDER BY max_score DESC
LIMIT X
) top_scores
ON top_scores.name = t.name
GROUP BY t.name
) top_last
on t.name = top_last.name
and t.date = top_last.date;

More concise SQL query involving MAX()

inventory
+------------------+-------------------+------------+
| DVD | replacement_price | stock |
+------------------+-------------------+------------+
| Pi | 9.99 | 500 |
| Dune | 29.99 | 100 |
| Heathers | 4.99 | 20 |
| Jaws | 19.99 | 500 |
| Mulholland_Drive | 39.99 | 50 |
| Waking_Life | 29.99 | 200 |
+------------------+-------------------+------------+
rented
+-----------------+-----------+------------------+
| subscriber | queue_nbr | DVD |
+-----------------+-----------+------------------+
| Bob | 1 | Mulholland_Drive |
| Bob | 2 | Jaws |
| Chey | 1 | Pi |
| Chey | 2 | Heathers |
| Jamie | 2 | Mulholland_Drive |
| Jamie | 4 | Dune |
| Jamie | 1 | Jaws |
| Jamie | 3 | Waking_Life |
| Nora | 4 | Jaws |
| Nora | 2 | Mulholland_Drive |
| Nora | 3 | Dune |
| Nora | 1 | Waking_Life |
+-----------------+-----------+------------------+
I want to return ONLY the subscriber(s) with the priciest movie queue (think Netflix DVD replacement costs if you lost all the movies you had out at a given time). I've used MAX() rather than TOP, LIMIT or ROWNUM because the query needs to be as db-independent as possible and must return multiple subscribers in the event of a tie. Using the tables above, the result should be
+---------+
| highest |
+---------+
| Jamie |
| Nora |
+---------+
After much searching and experimentation, I've come up with code that works, but it seems to my novice eyes bloated and inefficient, both in quantity of code and execution.
Would anyone mind refactoring and explaining your code?
My code:
SELECT z.subscriber highest
FROM
(SELECT MAX(price) max_price
FROM (
SELECT subscriber_name subscriber, SUM(replacement_price) price
FROM inventory i
INNER JOIN rented r
ON i.DVD = r.DVD
GROUP BY subscriber
) x
) y
INNER JOIN
(
SELECT subscriber_name subscriber, SUM(replacement_price) price
FROM inventory i
INNER JOIN rented r
ON i.DVD = r.DVD
GROUP BY subscriber
) z
ON z.price = y.max_price
If you want to return only those with the max total, then you could use the following which works in both MySQL and SQL Server. It is not any more concise than your current query though:
select subscriber
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
having sum(replacement_price) = (select max(TotalCost)
from
(
select sum(replacement_price) TotalCost
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
) p);
If you are using SQL Server, then I would suggest implementing windowing functions, similar to this:
select subscriber
from
(
select subscriber,
rank() over(order by sum(replacement_price) desc) rnk
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
) src
where rnk = 1
See SQL Fiddle with Demo
SELECT z.subscriber
FROM(
SELECT RANK() OVER(ORDER BY SUM(replacement_price)) subscriber_rank,
r.subscriber subscriber,
SUM(replacement_price) totalReplacementPrice
FROM inventory i
INNER JOIN rented r ON i.dvd = r.DVD
GROUP BY subscriber
) z
WHERE z.subscriber_rank = 1
Some of your column names are different in you query from you sql sample, so I've used the column names given in the demo tables. I use the rank function in the inner query to find the order of all of the people ordering by the sum of the replacement_price. Then select the row(s) where the rank is 1.
Rank is available in both MS Sql Server and Oracle. To go much further than that as #bluefeet says you will need to give more detail as to which database you are targetting.

Mysql include column with no rows returned for specific dates

I would like to ask a quick question regarding a mysql query.
I have a table named trans :
+----+---------------------+------+-------+----------+----------+
| ID | Date | User | PCNum | Customer | trans_In |
+----+---------------------+------+-------+----------+----------+
| 8 | 2013-01-23 16:24:10 | test | PC2 | George | 10 |
| 9 | 2013-01-23 16:27:22 | test | PC2 | Nick | 0 |
| 10 | 2013-01-24 16:28:48 | test | PC2 | Ted | 10 |
| 11 | 2013-01-25 16:36:40 | test | PC2 | Danny | 10 |
+----+---------------------+------+-------+----------+----------+
and another named customers :
+----+---------+-----------+
| ID | Name | Surname |
+----+---------+-----------+
| 1 | George | |
| 2 | Nick | |
| 3 | Ted | |
| 4 | Danny | |
| 5 | Alex | |
| 6 | Mike | |
.
.
.
.
+----+---------+-----------+
I want to view the sum of trans_in column for specific customers in a date range BUT ALSO include in the result set, those customers that haven't got any records in the selected date range. Their sum of trans_in could appear as NULL or 0 it doesn't matter...
I have the following query :
SELECT
`Date`,
Customer,
SUM(trans_in) AS 'input'
FROM trans
WHERE Customer IN('George','Nick','Ted','Danny')
AND `Date` >= '2013-01-24'
GROUP BY Customer
ORDER BY input DESC;
But this will only return the sum for 'Ted' and 'Danny' because they only have transactions after the 24th of January...
How can i include all the customers that are inside the WHERE IN (...) function, even those who have no transactions in the selected date range??
I suppose i'll have to join them somehow with the customers table but i cannot figure out how.
Thanks in advance!!
:)
In order to include all records from one table without matching records in another, you have to use a LEFT JOIN.
SELECT
t.`Date`,
c.name,
SUM(t.trans_in) AS 'input'
FROM customers c LEFT JOIN trans t ON (c.name = t.Customer AND t.`Date` >= '2013-01-24')
WHERE c.name IN('George','Nick','Ted','Danny')
GROUP BY c.name
ORDER BY input DESC;
Of course, I would mention that you should be referencing customer by ID, and not by name in your related table. Your current setup leads to information duplication. If the customer changes their name, you now have to update all related records in the trans table instead of just in the customer table.
try this
SELECT
`Date`,
Customer,
SUM(trans_in) AS 'input'
FROM trans
inner join customers
on customers.Name = trans.Customer
WHERE Customer IN('George','Nick','Ted','Danny')
GROUP BY Customer
ORDER BY input DESC;