MySQL query - Using multiple tables - php

I have 4 tables. (Simplified the 4 tables for the question)
Table 1: Supplier - Id, Type, TypeId, ExpiryDate
Table 2: SupplierType1 - Id, UserId, SupplierName
Table 3: SupplierType2 - Id, UserId, SupplierName
Table 4: User - Id, Name
All Id's are simply auto-increments in their tables.
In Supplier:
'Type' refers to either SupplierType1 or SupplierType2
'TypeId' is the 'Id' from either SupplierType1 or SupplierType2.
In both SupplierType1 and SupplierType2:
'UserId' is the Id from User
I have the 'UserId' (shown as X below). I want to return a list of which has these columns:
Supplier.Id, SupplierType1.RetailName, ExpiryDate
Where (SupplierType1.UserId == 'X' AND Supplier.TypeId == SupplierType1 AND Supplier.ExpiryDate < CurrentDate)
I've only recently starting using mysql and my current solutions seem way too cumbersome. Keen to learn a better way to do this. I would appreciate the help. Thanks in advance!

query
$qry = "
SELECT *
FROM Supplier s
LEFT JOIN SupplierType1 s1 ON s1.id=s.TypeId
LEFT JOIN User u ON u.Id=s1.UserId
WHERE s1.UserId='X' AND s.TypeId='SupplierType1' AND s.ExpiryDate<CURDATE()
";

Related

What join to use

I have two tables, one for registered users and one to store votes.
We are logging in with registrants.id and registrants.zipcode. Once they vote their votes are inserted into the votes table, along with their Registration ID.
Im trying to right a select statement that returns a record that will select all the records for Matched ID and Zipcode, but the ID is not in the Votes.voter column. i have tried all kinds of variations of all the joins i can think of. is it something simple i am missing.
SELECT * FROM registrants
LEFT JOIN votes on registrants.id = votes.voter
WHERE registrants.id = 1 AND registrants.zipcode = 46706 and votes.voter <> 1
Perhaps a not exists query:
select * from registrants
where registrants.zipcode = '46706'
and not exists (select 1 from votes where registrants.id = votes.voter)

PHP mySQL - Get data from 3 tables from database

I have 3 tables with their columns, I would like to fetch those students who haven't taken the quiz and those who already took the quiz (separate scripts)
Table quiz
Column id, title, created_at, start_on, end_on, class_name, user_faculty
Table studentclass
Column id, class_name, user_faculty, user_student
Table score
Column id, grade, user_student, status, quiz_id
Where as quiz.class_name = studentclass.class_name, quiz.user_faculty = sctudentclass.user_faculty, studentclass.user_student = score.user_student and quiz.id = score.quiz_id
score.status = 'F' //this defines that the user_student already took the quiz
My query is:
SELECT quiz.id, quiz.title, quiz.start_on, quiz.end_on, quiz.class_name,
quiz.user_faculty, studentclass.user_student, score.status
FROM quiz
INNER JOIN studentclass
ON quiz.class_name = studentclass.class_name
AND start_on >= now()
AND end_on <= now()
LEFT JOIN score
ON quiz.id = score.quiz_id
WHERE score.status IS NULL
If the user_student already took the quiz then he is unable to see the quiz anymore because he already has a row in the score table with the user_student, quiz_id and status. But other user_student who haven't taken the quiz can see the quiz.
I hope you get what I want to figure out.
The following query would list all the student who havnt taken the quiz. Let me know if it serves your purpose. I'll update it as per the need.
You can add the joins accordingly if you want the data from other tables.
select * from studentclass Where id NOT IN (
select user_student from score where quiz_id = YOUR ID //if you wnat to filter it for a specific quiz.
)

How to UPDATE rows in one table where there duplictaes in another

I would be massively grateful if someone can help me write a query to update our orders system due to a dupe issue.
We have an orders table and a customers table.
I've identified some duplicate rows in our customers table where the email address and password are the same on unique rows - and are associated with unique live orders by CustomerNumber which exists in each table. This is bad as when a customer logs in to their account, they won't see all of their orders, rather they'll only see the orders associated with the highest customer ID (see login SQL below)
Identify duplicate user accounts:
SELECT
emailaddress,
PASSWORD,
count(*)
FROM
scustomers
JOIN orders ON orders.customernumber = customers.CustomerNumber
WHERE Completed = 1
GROUP BY
emailaddress,
PASSWORD
HAVING
count(*) > 1
Login SQL:
SELECT * FROM scustomers WHERE EmailAddress = :EmailAddress AND (Password = :Password) ORDER BY CustomerNumber DESC LIMIT 0,1
I need to write a query that:
Updates the "orders" table
Updates the "CustomerNumber" column
Sets the "CustomerNumber" column to be the highest "CustomerNumber"
WHERE the "customers" table has more than 1 rows with has an
identical "Email" and "Password" column
Where do I start?!
Our system has been fixed so that any customer order a new product by logging in will always use the highest possible associated CustomerNumber so this really is about fixing existing data.
UPDATE:
I've never used SQL Fiddle, but here is some sample data that I hope will help you.. help me!
CUSTOMERS:
customernumber, email, password
3272, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
10001, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
ORDERS:
ordernumber,customernumber,status
123457, 3272, 'LIVE'
123456, 10001, 'LIVE'
I need to update OrderNumber: 123457 to have the CustomerNumber of 10001, not 3272.
Step 1 : create a temporary column to store the correct CustomerNumber
ALTER TABLE scustomers
ADD COLUMN id_tmp INT NOT NULL;
Step 2 : retrieve the correct CustomerNumber
UPDATE scustomers
INNER JOIN
(
SELECT
emailaddress,
PASSWORD,
MAX(CustomerNumber) AS id
FROM
scustomers
GROUP BY
emailaddress,
PASSWORD
) AS duplicate ON scustomers.emailaddress = duplicate.emailaddress AND scustomers.PASSWORD = duplicate.PASSWORD
SET id_tmp = id;
Step 3 : update order table with the correct CustomerNumber
UPDATE orders
INNER JOIN scustomers ON orders.customerNumber = customers.CustomerNumber
SET orders.customernumber = id_tmp;
Step 4 : delete duplicate customers
DELETE FROM scustomers
WHERE customernumber <> id_tmp;
Step 5 : remove the temporary column
ALTER TABLE scustomers
DROP COLUMN id_tmp;
I am just giving idea about sql query you need to write for loop
SELECT GROUP_CONCAT( customernumber) , i.email
FROM scustomers i INNER JOIN ( SELECT k.email FROM scustomers k GROUP BY k.email
HAVING COUNT( `customernumber` ) >1 )j ON i.email = j.email GROUP BY i.email
Out put :
----------------------------
customernumber Email
---------------------------
1,2,3 ss#ss.ss
After this all duplicate will come in on field.explode the new customernumber get last value in that array (Ex: 3 is last value)
update `orders` set `customernumber`='last array value(Ex: 3)' WHERE `customernumber` in (customernumber from above query(1,2,3) )
For delete duplicate records
DELETE n1 FROM scustomers n1, scustomers n2 WHERE n1.customernumber< n2.customernumber AND n1.email= n2.email

Getting data from 3 MySQL tables

I'm having a struggle here trying to grab some data from 3 database tables..
The idea is that users can fill out their profile with several fields, and I'm storing every profile field, field values and the users selected value in separate tables.
The structure of the tables look like this:
Table 'profile_fields'
- id
- name
- sort
- status (enum '0', '1')
Table 'profile_field_values'
- id
- profile_field_id
- name
Table 'user_profile_fields'
- user_id
- profile_field_id
- profile_field_value_id
Would be really nice if you could tell me how to construct this query, and why you used the JOIN you did.
Also, how would this table layout scale when the userbase grows?
Thank you so much in advance!
Edit:
OK, I still can't figure out how to make it return all the fields from 'profile_fields' along with the users selected option from 'user_profile_fields'. If the user hasn't selected a value, it should just be null.
This is my (non-functional) query so far:
SELECT PF.id AS field_id, PF.name AS field_name, UPF.profile_field_value_id AS value_id, PF.type, PFV.name
FROM profile_fields PF
LEFT JOIN profile_fields_values PFV ON PFV.profile_field_id = PF.id
LEFT JOIN user_profile_fields UPF ON UPF.user_id=1 AND PF.id = UPF.profile_field_id
WHERE length(PF.name) > 0 and PF.status = '1'
ORDER BY PF.sort
This query seems to work, but it does not fetch the name of the value from 'profile_field_values':
SELECT PF.id AS field_id, PF.name AS field_name, UPF.profile_field_value_id AS value_id, PF.type
FROM profile_fields PF
LEFT JOIN user_profile_fields UPF ON UPF.user_id =1
AND PF.id = UPF.profile_field_id
WHERE LENGTH( PF.name ) >0
AND PF.status = '1'
ORDER BY PF.sort
I think you have some unnecessary complexity in there. Maybe you should try
Table 'profile_fields'
id
name
sort
status (enum '0', '1')
Table 'profile_field_values'
id
user_id
profile_field_id
value
why are there 3 tables?
Seems like simple JOINs should work:
SELECT pf.id, pf.name, pf.sort, pf.status,
pfv.id, pfv.profile_field_id, pfv.name,
upf.user_id, upf.profile_field_id, upf.profile_field_value_id
FROM profile_fields pf
INNER JOIN profile_field_values pfv
ON pf.id = pfv.profile_field_id
INNER JOIN user_profile_fields upf
ON upf.profile_field_value_id = pfv.id AND upf.profile_field_id = pf.id
A Visual Explanation of SQL Joins
This uses an INNER JOIN to select all matching records from each table -- review the post to tell the difference between an INNER and an OUTER join.

How to select a column value as a column name and group the results as a row

How do I select a column value as a column name and group the results as a row.
I have a table as such:
id articleId label value
1 1 title Example title
2 1 description This is the description
3 1 author Me
4 2 title Example of another type of article
5 2 description Short description
6 2 author Someone else
Is it possible to select all of the rows and use the label as the column name and the value as the value of that column name and then group them by the article name.
So how I would like to have it returned:
articleId title description author
1 Example title This is the.. Me
2 Example of an.. Short descr.. Someone else
I'm using this for a CMS where the user can define the fields for an article so we don't have to customize the table's. This is why i'm not making the tables as the I would like to have it returned. I am also aware that I can just as easily convert the result to this in php.
-- edit --
Can this be done without knowing what labels are added? In this example im using title, description and author. But it could very well be something totally different like title, shortDescription, availableTo, techInformation, etc.. The idea is that the article's are customizable for the user without needing to change the database and query's
I figured I'd better post as an answer, even if not what OP would like to hear. What you are asking to do is to populate a query with a variable number of columns based on the distinct values within column label, all associated with articleID. Taking your specific example, the following would be the resultant query that I would most likely go to in this instance (though the example from #Devart is equally valid)
SELECT
t.id,
t.articleId,
t1.value AS title,
t2.value AS description,
t3.value AS author
FROM `tableName` t
LEFT JOIN `tablename` t1
ON t1.article_id = t.article_id AND t1.label = 'title'
LEFT JOIN `tablename` t2
ON t2.article_id = t.article_id AND t2.label = 'description'
LEFT JOIN `tablename` t3
ON t3.article_id = t.article_id AND t3.label = 'author'
Now expanding this to account for up to n labels, we get the following query (metacode included, this query will NOT execute verbatim)
SELECT DISTINCT label FROM `tableName`;
SELECT
t.id,
t.articleId
// for (i=1;i<= number of distinct labels) {
,t[i].value AS [value[i]]
// }
FROM `tableName` t
// for (i=1;i<= number of distinct labels) {
LEFT JOIN `tablename` t[i]
ON t[i].article_id = t.article_id AND t[i].label = [value[i]]
// }
;
So what you can do is one of the following.
SELECT t.* FROM tablename t and then have PHP process it as required
SELECT DISTINCT label FROM tablename and have PHP build the second query with the many LEFT JOINs (or MAX / GROUP BY logic if preferred)
Create a Stored Procedure to do the same as #2. This would most likely be more efficient than #2 however may be less efficient overall than #1.
You can use pivote table trick -
SELECT
articleId,
MAX(IF(label = 'title', value, NULL)) AS title,
MAX(IF(label = 'description', value, NULL)) AS description,
MAX(IF(label = 'author', value, NULL)) AS author
FROM
table
GROUP BY
articleId
Try below :
select t1.articleId,t1.title,t1.description,t1.author
from tablename as t1
left join (select max(articleId) as articleId
from tablename
group by articleId ) as t2
on t1.articleId=tsm.articleId where [.....]

Categories