Complex MySQL select with 2 foreign keys - mysql

I am attempting to do a select between 3 tables. The only problem is that one of the tables is used to resolve foreign keys on 2 different tables. A short description of the tables can be found below. I have removed some columns so that only pertinent ones are shown.
mail_addr
+------------+
| id |
+------------+
| email |
+------------+
msg_rcpt
+------------+
|MsgID |
+------------+
|rid |
+------------+
|content |
+------------+
msgs
+------------+
|MsgID |
+------------+
|sid |
+------------+
|msgTime |
+------------+
|size |
+------------+
I have attempted...
SELECT msg_rcpt.MsgID, msg_rcpt.content, mail_addr.email as rcpt_addr, msgs.msgTime
FROM msg_rcpt
JOIN msgs ON msgs.MsgID = msg_rcpt.MsgID
JOIN mail_addr ON msg_rcpt.rid = mail_addr.id
JOIN mail_addr ON msgs.sid = mail_addr.id
When I do these joins it comes back with Not unique table/alias: 'mail_addr'.
I know this is wrong but I am unsure how or even what I should be looking for in order to resolve this query.
Any feedback would be appreciated.
Viper

You can join a table multiple times, but you HAVE to alias the 2nd and subsequent joins:
JOIN mail_addr ON msg_rcpt.rid = mail_addr.id
JOIN mail_addr AS someaslias ON msgs.sid = somealias.id
^^^^^^^^^^^^^ ^^^^^^^^^

If you wanna join two times on the same table, you'll have to use aliases (well at least one, but two aliases will make things clearer).
SELECT msg_rcpt.MsgID, msg_rcpt.content, m1.email as rcpt_addr, msgs.msgTime
FROM msg_rcpt
JOIN msgs ON msgs.MsgID = msg_rcpt.MsgID
JOIN mail_addr m1 ON msg_rcpt.rid = m1.id
JOIN mail_addr m2 ON msgs.sid = m2.id

I did not understand if this is the result you want to achieve but this should work (based on your example query)
SELECT msg_rcpt.MsgID, msg_rcpt.content, m1.email as rcpt_addr, msgs.msgTime
FROM msg_rcpt JOIN msgs ON msgs.MsgID = msg_rcpt.MsgID
JOIN mail_addr m1 ON msg_rcpt.rid = m1.id
JOIN mail_addr m2 ON msgs.sid = m2.id
If this is not what you're expecting, please edit your question adding an example of the final result!

Related

SQL Distinct based on different colum

I have problem to distinct values on column based on other column. The case study is:
Table: List
well | wbore | op|
------------------
wella|wbore_a|op_a|
wella|wbore_a|op_b|
wella|wbore_a|op_b|
wella|wbore_b|op_c|
wella|wbore_b|op_c|
wellb|wbore_g|op_t|
wellb|wbore_g|op_t|
wellb|wbore_h|op_k|
So, I want the output to be appear in different field/column like:
well | total_wbore | total_op
----------------------------
wella | 2 | 3
---------------------------
wellb | 2 | 2
the real study case come from different table but to simplify it I just assume this case happened in 1 table.
The sql query that I tried:
SELECT well.well_name, wellbore.wellbore_name, operation.operation_name, COUNT(*)
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name,wellbore.wellbore_name
HAVING COUNT(*) > 1
But this query is to calculate the duplicate row which not meet the requirement. Anyone can help?
you need to use count distinct
SELECT
count(distinct wellbore.wellbore_name) as total_wbore
count(distinct operation.operation_name) as total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
Final query:
SELECT
well.well_name,
COUNT(DISTINCT wellbore.wellbore_name) AS total_wbore,
COUNT(DISTINCT operation.operation_name) AS total_op
FROM well
INNER JOIN wellbore ON wellbore.well_uid = well.well_uid
INNER JOIN operation ON wellbore.well_uid = operation.well_uid
GROUP BY well.well_name

Static SQL query replace to dynamic column

I have following query:
http://www.sqlfiddle.com/#!9/752e34/3
This query use SELECT in SELECT queries.
"SELECT a.*
,(SELECT s.value FROM tbl_scd AS s WHERE s.tag_id = 1 AND s.main_id = a.id ORDER BY s.date_time DESC LIMIT 1) AS title
,(SELECT s.value FROM tbl_scd AS s WHERE s.tag_id = 2 AND s.main_id = a.id ORDER BY s.date_time DESC LIMIT 1) AS alt
FROM tbl_main AS a
WHERE 1;"
Now I'm looking for a solution to add a new row into tbl_tag without change the above query (that the SELECT in SELECT part will be dynamic) to get a reference to tbl_tag
To get this:
+----+---------------+-----------+-----------+--------------+
| id | date | title | alt | new_column |
+----+---------------+-----------+-----------+--------------+
| 1 | 2018-10-10 | test1-1 | test1-3 | NULL |
| 2 | 2018-10-11 | test2-1 | test2-1 | NULL |
+----+---------------+-----------+-----------+--------------+
It would be great to get an idea or help.
Thanks
Your last comment on your question about using JOIN makes it clearer to me (I think) what you are after. JOINs will definitely help you a lot here, in place of the rather cumbersome query you are currently using.
Try this:
SELECT
tbl_main.date,
tblA.value AS title,
tblB.value AS alt
FROM
tbl_main
INNER JOIN (SELECT main_id, tag_id, value
FROM tbl_scd
INNER JOIN tbl_tag ON (tbl_scd.tag_id = tbl_tag.id)
WHERE tbl_tag.name = 'title') tblA
ON (tbl_main.id = tblA.main_id)
INNER JOIN (SELECT main_id, tag_id, value
FROM tbl_scd
INNER JOIN tbl_tag ON (tbl_scd.tag_id = tbl_tag.id)
WHERE tbl_tag.name = 'alt') tblB
ON (tbl_main.id = tblB.main_id);
I think this will get you much closer to a general solution to what it looks like you are trying to achieve, or at least point you in a good direction with using JOINs.
I also think you might benefit from re-thinking your database design, because this kind of pivoting rows from one table into columns in a query output can be an indicator that the data might be better off structured differently.
In any case, I hope this helps.

How can this be done in a single select statement?

I've got these three tables in the DB & I want to select the event_name for a specific userID from t1event given that I know the value of ID from t1user. How can I do this in a single select statement. (I am using mysql).
**t1user**
+----+
| ID |
+----+
**t2userEvent**
+---------+----------+
| userID | eventID |
+---------+----------+
**t1event**
+----------+--------------+
| eventID | event_name |
+----------+--------------+
Use join:
SELECT t1user.ID, t1event.event_name
FROM t1user
JOIN t2userEvent ON t1user.ID = t2userEvent.userID
JOIN t1event ON t1event.eventID = t2userEvent.eventID
WHERE t1user.ID = :user_id
If you want the users who doesn't have events be listed too, then use LEFT JOIN instead.
You could try this:
SELECT A.event_name FROM t1event A INNER JOIN t2userEvent B
ON A.eventID = B.eventID WHERE b.userID = ?
If I understand it correctly you have the userID as parameter?

sql query seems to return no result

Certain queries that work fine in the mysql command line client don't seem to return
anything at all (no error, no result) in phpMyAdmin.
I get the impression it's related to nested queries.
Here's an example:
select * from
(select
(select min(data) from census2 where
census2.monkey=samplecollection.monkeyid and
date(collectiontime)=date(census2.timestamp)) census
from samplecollection,biograph,hormone,plate
where plate.hormone='Testosterone' and hormone.plateid=plate.plateid and
not specialcontentcode like '%UR%' and thermos!='F' and
biograph.id=monkeyid and samplecollection.sampleid=hormone.sampleid)
t1 limit 3;
+--------+
| census |
+--------+
| GFF |
| GRF |
| GRF |
+--------+
3 rows in set (5.09 sec)
If I extract the inner query (and put the limit on it) then I get a result.
The structure of your query if too complex and clearly not optimized and it may cause the problem you've releved.
Here is the same query with a bit of refactoring:
SELECT *
FROM samplecollection SC
INNER JOIN (SELECT C2.monkeyid
,MIN(C2.data) AS [census]
FROM census2 C2
INNER JOIN samplecollection SC2 ON SC2.monkeyid = C2.monkey
AND DATE(SC2.collectiontime) = DATE(C2.timestamp)
AND SC2.thermos != 'F'
AND SC2.specialcontentcode NOT LIKE '%UR%'
GROUP BY C2.monkeyid) T ON T.monkeyid = SC.monkeyid
INNER JOIN biograph B ON B.id = SC.monkeyid
INNER JOIN hormone H ON H.sampleid = SC.sampleid
INNER JOIN plate P ON P.plateid = H.plateid
AND P.hormone = 'Testosterone'
LIMIT 3
The answer comes late but it may be useful for some people to see how some very complex query structures can be simplified when using JOIN clauses.
Hope this will help.

Retrieve data from another table

I have a table like
tbl_scripts
script_unique_id | system_id | script_name
+-----------------------------------------+
12345 | 89784 | Demo
And another table goes as
tbl_allowed_group_ids
system_id | script_unique_id |allowed_group_id
+---------------------------------------------+
89784 12345 56987
So now what I want is the row from tbl_scripts with group_id only if the unique id is in allowed_group_id
What I tried is this but is nowhere close to it....I know this is completely wrong
SELECT script_name FROM tbl_scripts WHERE script_unique_id = allowed_group_id
You will want to JOIN the tables:
select *
from tbl_scripts s
left join tbl_allowed_group_ids g
on s.system_id = g.system_id
and s.script_unique_id = g.script_unique_id
See SQL Fiddle with Demo
If you need help learning join syntax, here is a great visual explanation of joins.
A LEFT JOIN will return all rows in the tbl_scripts table regardless of whether or not it has a matching row in the tbl_allowed_group_ids table. If you only want matching rows, then you can use an INNER JOIN
JOIN the two tables:
SELECT t1.script_name
FROM tbl_scripts t1
INNER JOIN tbl_allowed_group_ids t2 ON t1.script_unique_id = t2.allowed_group_id