Screwy MySQL Code Logic - php

The default_albums table is used for storing album data.
The default_hottest_categories table is used to store the category
data
The default_album_hc_connect table is used to connect the default_hottest_categories table with the default_albums
table.
I need to be able to display all albums that are apart of the category which is_hottest. the is_hottest column is located in the default_hottest_categories table. The below code is what I have so far:
$q1 = $this->db->query("SELECT * FROM default_albums a, default_hottest_categories d INNER JOIN default_album_hc_connect dc
ON d.id = dc.hottest_categories_id INNER JOIN default_albums ON dc.albums_id = default_albums.album_id
WHERE d.is_hottest = 'Yes'");
I really do not know if this is correct or not. So if you can help me, I'd much appreciate it.

This should work. You had an extra instance of the default_albums table in your FROM clause. I removed that. Also you generally want to join all your tables together. The comma you had in there is used for CROSS JOINS, but is not used that often and is not needed in this case. Also I would recommend only taking the fields you need in your SELECT clause.
SELECT *
FROM default_albums a
INNER JOIN default_album_hc_connect dc
ON a.albums_id = dc.album_id
INNER JOIN default_hottest_categories d
ON dc.hottest_categories_id = d.id
WHERE d.is_hottest = 'Yes'"

Related

Dynamically created sql not happy

I have a table which contains records of a 'widget' many of the columns contain just the Id of a record in a different table. When editing the widget record users are allowed to do a save even if it is incomplete. They can open it later and continue.
The problem I have, is when it is incomplete my query returns nothing because the where clause contain fields which have default 0 in them and there is no match in the other tables. Here is a sample of script which illustrates this problem.
select Client,Make,Model,Shape
from
widget,clients,makes,models,shapes
where
widget.ClientId = '3' and
widget.MakeId = makes.Id and
widget.ModelId = models.Id and
widget.ShapeId = shapes.Id
I am building this query dynamically using PHP so am trying to keep it as simple as possible. All sugestions welcome, thanks.
The problem is that you are using an implicit inner join (implicit meaning that you do the join in the where clause). Inner joins return matching records only, therefore if some of the data are incomplete, no records will be returned.
Use an outer join instead, that return all records from one of the tables in the join and the matching records from the other table (MySQL does not support full outer join, but this is not relevant here anyway).
Based on your description widget table is your main table, so use left join to join all other tables on widget to get the widget even if it is incomplete:
select c.Client, m.make, md.model, s.shape
from widget w
left join clients c on c.id = w.ClientId
left join makes m on m.id = w.MakeId
left join models md on md.id = w.ModelId
left join shapes s on s.id = w.ShapeId
select c.Client, m.make, md.model, s.shape
from widget w
join clients c on c.id = w.ClientId
join makes m on m.id = w.MakeId
join models md on md.id = w.ModelId
join shapes s on s.id = w.ShapeId
Use Joins instead of multiple tables in FROM Clause.
Instead of direct join use LEFT JOIN so that no matter if there is records from other tables, still first table entries will be returned:
SELECT Client, Make, Model, Shape
FROM widget
LEFT JOIN clients ON widget.ClientId = widget.Id
LEFT JOIN makes ON widget.MakeId = makes.Id
LEFT JOIN models ON widget.ModelId = models.Id
LEFT JOIN shapes ON widget.ShapeId = shapes.Id
WHERE widget.ClientId = 3
Table columns should be in lower case
Table names should be in singular form, e.g. model, shape
Foreign keys should be in other table. Instead of widget having ModelId, model should have widget id
I may be wrong if relations are different

How to join all three tables in MYSQL?

I have a MySQL database that has three tables holding information about uploaded photos by users. I have a PHP page that displays all the photos in the database (tbl_uploads) and who uploaded them (tbl_users). To display the photos and who uploaded them I have a join in the MySQL query.
SELECT *
FROM tbl_uploads, tbl_users
WHERE tbl_uploads.user_id = tbl_users.user_id
ORDER BY date DESC
I now want to join a third table tbl_collab to the MySQL query that allows me to display all the users that collaborated with the photo (a form allows them to post the $file and their $user_id to tbl_collab). I guess I need to add a join from tbl_uploads.file with tbl_collab.user_id but I'm not sure how.
tbl_users
|//**user_id**//|int(11)|No|
|user_name|varchar(25)|No|
|user_email|varchar(60)|No|
|user_password|varchar(255)|No|
|joining_date|datetime|No|
tbl_uploads
|//**id**//|int(10)|No|
|file|varchar(100)|No|
|type|varchar(30)|No|
|size|int(11)|No|
|user_id|int(11)|No|
|user_name|varchar(25)|No|
tbl_collab
|//**id**//|int(11)|No|
|user_name|varchar(100)|No|
|user_id|int(11)|No|
|file|varchar(255)|No|
I have been trying your various suggestions and I can't really get them to work as I would hope so I have made a mysql fiddle that might be help me.
The problem is that when I loop through the rows that the query throws up in PHP I ether get just the rows where there is join with tbl_uploads.file and tbl.collab.file or I get the multiple rows duplicating themselves.
I'd suggest preferring ANSI SQL syntax for joins (over mentioning multiple tables in the "from" clause) as once the queries get complex I find the ANSI syntax easier to follow. Using that syntax, joining multiple tables is no big deal. e.g.,
SELECT uploads.<column>, users.<column>, collabs.<column>
FROM tbl_uploads uploads
JOIN tbl_users users ON users.user_id=uploads.user_id
JOIN tbl_collabs collabs ON collabs.file=uploads.file
ORDER BY uploads.date DESC
(Note, replace <column> above with the names of columns you want to select from the respective tables, using AS syntax to provide unique names where necessary.)
Consider that you will probably want to create indexes over the fields in the join conditions for performance if you expect the database will become large. You may also want to use left joins when joining, e.g., tbl_collabs if it is possible an upload will have no collaborators, otherwise the query will return no data if there are no matching rows in tbl_collabs.
The first thing to do is to normalize your data. If you look closely, username appears in all three tables. It shouldn't. It belongs only in the users table. Then your other tables need to have a user_id field instead of the username.
tbl_uploads
|//**id**//|int(10)|No|
|file|varchar(100)|No|
|type|varchar(30)|No|
|size|int(11)|No|
|user_id|int(11)|No|
tbl_collab
|//**id**//|int(11)|No|
|user_id|int(11)|No|
|file|varchar(255)|No|
In both cases the user_id is a foreign key to the id field in the users table. Now we have something consistent to join on.
SELECT * FROM tbl_uploads
INNER JOIN tbl_users ON tbl_uploads.user_id = tbl_users.user_id
INNER JOIN tbl_collab ON tbl_collab.file = tbl_uploads.file
Whether you should use INNER JOIN or LEFT JOIN depends on exactly what you need to do with your data, but INNER JOIN seems more appropriate based on information provided.
Update: As #drew pointed out, none of your tables have a column named date did you perhaps intend to sort by tbl_users.joining_date?
Seems the join is on file to me
SELECT *
FROM tbl_uploads
inner join tbl_users on tbl_uploads.user_id = tbl_users.user_id
inner join tbl_collab on tbl_collab.file = tbl_uploads.file
ORDER BY date DESC
You can just add another join condition. Also, note that implicit joins (having multiple tables in the from clause) isn't considered a good practice, and you should probably use explicit join clauses:
SELECT *
FROM tbl_uploads up
JOIN tbl_users us ON up.user_id = us.user_id
JOIN tbl_collab c ON c.user_id = up.user_id
ORDER BY date DESC

Get information from another table using intermediate table

Here I have three tables authors, books_has_authors and books.
Books_has_author is an intermediate table which contains only the primary keys form other two tables. I am trying to write an sql query which will return me all the books name written by a particular author. I am new to relational database concepts as well as writing queries for relational databases. I know some join queries but I'm really confused how to use them for fetching information through an intermediate table. Any help will be appreciated ! :)
You only need to add an additional JOIN, like this:
SELECT b.book_id, b.book_name, a.author_id, a.author_name
FROM books b
JOIN books_has_author ba ON ba.books_book_id = b.book_id
JOIN author a ON ba.author_author_id = a.author_id
WHERE a.author_id = xxx
Try this:
SELECT b.* FROM books b
INNER JOIN books_has_author bha
ON bha.books_book_id = b.book_id
WHERE bha.author_author_id = "$$YOUR AUTHOR ID"
use JOIN like that :-
SELECT *
FROM books
JOIN books_has_author ON books_has_author.books_book_id = books.book_id
JOIN author ON books_has_author.author_author_id = author.author_id
WHERE author.author_id = '123'

Mysql join for the following ER

I have the following table structure of my db:
tbl_project
tbl_employee
tbl_deliverable
user_to_deliverable
Where tbl_prjct and tbl_deliverable have a 1-to-many relationship,
tbl_employee and tbl_deliverable have many-many relationships so they are split into user_to_deliverable table.
I want a query to show project_name(from tbl_project), project's deliverables (from tbl_deliverable) and employee name which that specific deliverable is assigned to.
Can I get help writing this query?
Your desired query is much like 89.67% like this :D
SELECT a.ProjectName,
b.deliverables,
d.employeename
FROM tbl_project a
INNER JOIN tbl_deliverable b
ON a.projectID = b.projectID
INNER JOIN user_to_deliverable c
ON b.recordID = c.RecordID
-- or could be the primary key
INNER JOIN tbl_employee d
ON c.userID = d.userID
Approximate solution without knowing your schema. If you want the deliverables/employees concatenated for each project it would probably be best done by retrieving the results and parsing in a non-SQL language (PHP, Python, or whatever you are using). If you want this completely done in SQL you will need to use GROUP_CONCAT().
select tbl_project.name as project,
tbl_deliverable.name as deliverable,
tbl_employee.name as employee
from tbl_project
join tbl_deliverable
on (tbl_project.id = tbl_deliverable.project_id)
join user_to_deliverable
on (tbl_deliverable.id = user_to_deliverable.deliverable_id)
join tbl_employee
on (user_to_deliverable.employee_id = tbl_employee.id)

SQL left join automatic aliasing?

I just realized that I'm going to have to start aliasing my database calls due to repeating column names in my join tables. Is there a way to automatically tell SQL to alias all my column names so that they are returned with a prefix of the table name? Otherwise it appears to be quite confusing when only some of them are aliased. Just trying to be consistent without writing tons of extra code.
$sql = "SELECT contracts.po_number, contracts.start_date, contracts.end_date, contracts.description, contracts.taa_required, contracts.account_overdue, jobs.id AS jobs_id, jobs.job_number, companies.id AS companies_id, companies.name AS companies_name
FROM contracts
LEFT JOIN jobs ON contracts.job_id = jobs.id
LEFT JOIN companies ON contracts.company_id = companies.id
WHERE contracts.id = '$id'
ORDER BY contracts.end_date";
No, but you can make life a little easier by using table aliases:
SELECT c.po_number, c.start_date, c.end_date, c.description,
c.taa_required, c.account_overdue, j.id AS jobs_id, j.job_number,
cm.id AS companies_id, cm.name AS companies_name
FROM contracts c
LEFT JOIN jobs j ON c.job_id = j.id
LEFT JOIN companies cm ON c.company_id = cm.id
WHERE c.id = '$id'
ORDER BY c.end_date
you can use alias tables in your sql statements so you have to write less, but to actually access the columns from php there's no way around aliasing all of them, if you want to access them by name.
you can also access columns with indexes from php, but that's a maintenance nightmare
I would recommend to always alias table names. It makes it very hard to read later, if you skip alias.
For info, theres a gotcha in MySQL 5.6 (possibly others!)
SELECT *
FROM table1
LEFT JOIN table2 ON PKI = FKI
works as expected.. but recently I mispelt 'LEFT' as 'LEFY' in a query and it also worked but with a standard join! so therefore
SELECT *
FROM table1
LEFY JOIN table2 ON PKI = FKI
also works just fine as does any substitute for the word LEFY, so beware a typo changing your query !!

Categories