I've been trying to join another table with the table name matching a value in a column from another table.
If I hard-code the table name to a matching table like __gun it works fine but I cannot get the col value to be used + concat underscores to the beginning.
The problem lies in the left join here:
left join CONCAT('__', b.related_table) c on b.related_id = c.id
I need the related_table column to be used in the join. With __ before it.
Attempts:
SELECT a.*, c.*, b.equipable, b.related_table FROM inventory a
inner join items b on a.item_id = b.id
left join CONCAT('__', b.related_table) c on b.related_id = c.id
WHERE 1=1
and a.id = :inventory_id
and a.user_id = :user_id
SELECT a.*, c.*, b.equipable, b.related_table FROM inventory a
inner join items b on a.item_id = b.id
left join '__'+b.related_table c on b.related_id = c.id
WHERE 1=1
and a.id = :inventory_id
and a.user_id = :user_id
SELECT a.*, c.*, b.equipable, b.related_table FROM inventory a
inner join items b on a.item_id = b.id
left join "__"+Cast(b.related_table as nvarchar(4000)) c on b.related_id = c.id
WHERE 1=1
and a.id = :inventory_id
and a.user_id = :user_id
Thank you for considering my question
You cannot construct a table name.
Plan A: Rethink the schema. It is usually bad design to have multiple 'identical' tables.
Plan B: Write a Stored Procedure that uses CONCAT, PREPARE, EXECUTE, and DEALLOCATE_PREPARE to build and run the query.
You can do this using Prepared Statements or you can say dynamic SQL. Follow these steps :
Use SET for table name.
Use CONCAT to get the desired table name.
PREPARE statement for table created at step 1.
EXECUTE statement.
DEALLOCATE PREPARE to release the prepared statement.
Related
I am working on a project where multiple table data exists for a user but if empty one table from any of them then SQL return empty data even other tables data exist like below SQL
$id = 40;
SELECT *
FROM players a
JOIN pitcher b
ON a.id = b.user_id
JOIN outfield_position c
ON a.id = c.user_id
JOIN infield_position d
ON a.id = d.user_id
JOIN defensive_statistics e
ON a.id = e.user_id
JOIN career f
ON a.id = f.user_id
WHERE a.id = $id
like if $outfield_position table is empty then the SQL returns an empty array but sometimes maybe data here, what can I do if data available or not available every way can works?
Thanks
The default join used is inner join and as already explained here joins .
The output in this case will be intersection of the tables it is joined with,so if any table does not have any value then intersection will give empty result.
You can try with LEFT OUTER JOIN or FULL OUTER JOIN , in Left Outer Join if data is present in $players the value will be displayed.If unsure about the data Full Outer join will give all the results from all the tables.
I have 5 tables: a, b, c, d and e.
Each table is joined by an INNER JOIN on the id field.
My query is working perfectly fine as it is but I need to enhance it to count the result so I can echo it to the screen. I have not been able to get the count working.
There are very specific fields I am querying:
state_nm
status
loc_type
These are all parameters I enter manually into the query like so:
$_POST["state_nm"] = 'AZ'; ... // and for all other below values..
SELECT *
FROM main_table AS a
INNER JOIN table_1 AS b ON a.id = b.id
INNER JOIN table_2 AS c ON b.id = c.id
INNER JOIN blm table_3 AS d ON c.id = d.id
INNER JOIN table_4 AS e ON d.id = e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \ "%".$_ POST ["loc_type"]."%\"
AND b.STATUS = '".$_POST["status"]."'
GROUP BY b.NAME
ORDER BY c.county ASC;
not sure I get exactly what is your goal here.
anyway, using "select *" and group by in the same query is not recommended and in some databases will raise an error
what I would do is something like that:
select a.name, count(*) from (
SELECT * FROM main_table as a
INNER JOIN table_1 as b
ON a.id=b.id
INNER JOIN table_2 as c
ON b.id=c.id
INNER JOIN blm table_3 as d
ON c.id=d.id
INNER JOIN table_4 as e
ON d.id=e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \"%".$_POST["loc_type"]."%\"
AND b.status = '".$_POST["status"]."'
)a
group by a.name
the basic idea is to add an outer query and use group by on it...
hopefully this solves your problem.
In place of
SELECT *
in your query, you could replace that with
SELECT COUNT(*)
That query should return the number of rows that would be in the resultset for the query using SELECT *. Pretty easy to test, and compare the results.
I think that answers the question you asked. If not, I didn't understand your question.
I didn't notice the GROUP BY in your query.
If you want to get a count of rows returned by that query, wrap it in outer query.
SELECT COUNT(1) FROM (
/* your query here */
) c
That will give you a count of rows returned by your query.
Problem:
I'm trying to figure out how to join tables based on a condition in an SQL statement. I've spent an hour searching Google, SO, various websites and the MYSQL manual, but I just can't find the correct syntax for what I want to do.
I can't post the exact query I'm trying to get working, but I will post a simplified version for simplicity reasons.
Scenario:
Assuming I have three tables, a = person table, b = address table and c = car table.
Table b will always be joined to table a, becuase a person always lives at an address, but table c should only be joined to a if the value in the 'car_id' field is more than 0, because having a car is optional.
The query:
SELECT a.firstname, a.lastname, a.gender, a.address_id, b.address_firstline, b_address_secondline, b.postcode, c.car_manufacturer, c.car_model
FROM a
INNER JOIN b ON b.id = a.address_id
INNER JOIN c ON c.id = a.car_id AND a.car_id > 0
WHERE a.id = 1
The query above will run fine for a person with the id of 1 because he owns a car. However, if the query is run for a person with the id of 2, the query will return 0 rows because she does not own a car.
How do I make this second JOIN optional? I've tried using the IF ELSE statement, but I'm forever getting syntax errors. Could someone point me in the right direction here? Thanks in advance
You should use left outer join to join c with a.
SELECT a.firstname, a.lastname, a.gender, a.address_id, b.address_firstline, b_address_secondline, b.postcode, c.car_manufacturer, c.car_model
FROM a
INNER JOIN b ON b.id = a.address_id
LEFT OUTER JOIN c ON c.id = a.car_id AND a.car_id > 0
WHERE a.id = 1
Use LEFT JOIN instead of INNER JOIN on table c.
Unilateral joins work on this scenario.
A brief explanation.
a INNER JOIN b ON a.field1 = b.field1 returns every row for which both a.field1 and b.field1 exist and are equal
a LEFT JOIN b ON a.field1 = b.field1 returns every row from table a and returns every row in table b for which a.field1 = b.field1, and null values for non-matching values on table b.
RIGHT JOIN is analogous to LEFT JOIN
I'm coming across this situation alot, I'll have a query that will have one table needed in a join condition that may have no entries therefore requiring me to use a LEFT JOIN. I can't wrap my head around the syntax when it's used with more than 1 join.
I'll have:
SELECT A.*, B.*, C.*
FROM A, B, C
WHERE A.id = C.id
AND C.aid = A.id
AND B.cid = C.id
Along comes D with the possibility of being empty and I have to rewrite the query and run into problems.
How can I simply join D to any one of these tables?
You're much better off explicitly specifying all of your JOINs. That should make things much clearer.
SELECT A.*, B.*, C.*, D.*
FROM A
INNER JOIN C
ON C.aid = A.id
INNER JOIN B
ON B.cid = C.id
LEFT JOIN D
ON C.did = d.id
My advice is to never specify more than one column on FROM clause.
For clarity, it's better to always:
Use JOIN clause
Use aliases
Specify columns of joined tables on left side of equal sign
Example:
SELECT a.*, b.*, c.*
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
Not sure about MySQL, but in some other SQL flavors, you can use the same on UPDATES and DELETES, like:
DELETE FROM a
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
or
UPDATE a
SET something = newValue
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
The syntax below should help you. The basic premise is whatever table is listed LEFT is the required.. the table (or alias) on the right is optional. I understand you don't quite get it, and your syntax sample shows that (not meant to criticize) as you are joining from A -> C and C back to A on a different field. If this is the case where two fields are in the "C" table that BOTH point to A, you would re-join to A as a second alias...
select
Want.*,
Maybe.*,
SecondA.*,
B.*
From
A as Want
LEFT JOIN C as Maybe
on Want.ID = Maybe.ID
JOIN A as SecondA
on Maybe.AID = SecondA.ID
JOIN B
on Maybe.ID = B.cID
So, this query is stating I want everything from Table A (alias Want -- left side/first table in the list) Regardless of there being a match in Table C (alias Maybe) where the ID keys match.
Notice the next joins going down from "C" back to the second instance of "A" and table B. I have those as just joins... So the relationship between the "Maybe" alias, and that of second instance of "A" and "B" are JOIN (required).
Hopefully this gives some better clarification on HOW it works.
Now, for your real-life query. If you can describe what you are looking for, and your sample table structures / result expections, listing that could offer more explicit solution to your needs.
Hope this will help
SELECT
A.*, B.*, C.*
FROM A
inner join C on(A.id = C.id)
inner join B on(B.cid = C.id)
This is the query I'm performing (without some Joins that are not relevant):
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id
Each row of "a" is linked with 1 to 5 rows in "b".
The problem is that GROUP BY has performance issues (it takes 10x or more using GROUP BY than not using it). I need to retrieve only one row of each member in "a".
How can I make this faster?
edit: I need to be able to filter by a.id AND/OR c.id. The resultset I should be getting is only 1 row per "valid" member of "a", meaning the rows that match the constraints. Rows that don't match the filters shouldn't be returned.
In my original query, this would be done this way:
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id
a.id, b.id_anunciante, b.id_rubro, c.id are all indexes.
SELECT a.*,
(
SELECT c.id
FROM b
JOIN с
ON c.id = b.id_rubro
WHERE b.id_anunciante = a.id
-- add the ORDER BY condition to define which row will be selected.
LIMIT 1
)
FROM a
Create the index on b (id_anunciante) for this to work faster.
Update:
You don't need the OUTER JOINs here.
Rewrite your query as this:
SELECT a.*, c.id
FROM a
JOIN b
ON b.id_anunciante = a.id
JOIN c
ON c.id = b.id_rubro
WHERE a.id = 1
UNION ALL
SELECT a.*, 1
FROM a
WHERE EXISTS
(
SELECT NULL
FROM c
JOIN b
ON b.id_rubro = c.id
WHERE c.id = 1
AND b.id_anunciante = a.id
)
Add ORDER BY NULL to avoid the implicit sorting MySQL does when doing a group by.
I suppose you have indexes/PKs on a.id, b.id_anunciante, b.id_rubro and c.id ? I guess you could try adding a composite index on (b.id_anunciante, b.id_rubro) if your mysql version is not able to do an index merge.