Is there any way I could use php+mysql to do multiple criteria search?
I saw it on a website, and i want to make something similar for myself.
So I have two tables
table1- 'Books' (title, author, BookID)
table2- 'Descriptions' (Bookid, descriptions)
Each book can have as many descriptions as the users want it to have.
Table 'Books'
Title Author BookID
Nightmare (…) Tom B. AAA
Wonderful (…) Jim C. AAB
Ghost Night (…) Amy D. AAC
Babysitter (…) Kitty D. AAD
Hello world (…) Pete P. AAE
Hannibal (…) Butter H. AAF
and
table 'Descriptions'
Book ID Description Relevance
AAA Thriller 0
AAA Crime 0
AAA Detective 0
AAB Geography 0
AAB Travel 0
AAC Thriller 0
AAD Comedy 0
AAD Family 0
AAE Programming 0
AAE Computer Science 0
AAF Thriller 0
AAF Crime 0
I have already made the insert data part, it's actually not that hard for me, but when it comes to the searching part, things become way more complicated than I thought it would be.
the sheet I'll be using is the exact same model my ‘target’ website uses,here i use () to represent html's select form, and [] to represent ordinary input form
[ ]
(AND/OR) [ ]
(AND/OR) [ ]
(AND/OR) [ ]
and users can fill it 1-4 criteria, for example, "thriller" (AND) "Crime", and the MySQL would find all the descriptions that fit these descriptions, in my case, it would be these informations:
AAA Thriller 0
AAA Crime 0
AAC Thriller 0
AAF Thriller 0
AAF Crime 0
And next step the computer should categorize the ID found and sort the results into this:
AAA 2 criteria verified
AAF 2 criteria verified
AAC 1 criteria verified
and after that, i want it to echo/print these information onto the browser:
1. Nightmare (…) Tom B. AAA
descriptions: Thriller, Crime
2. Hannibal (…) Butter H. AAF
descriptions: Thriller, Crime
3. Ghost Night (…) Amy D. AAC
descriptions: Thriller
my main problem is the categorizing and sorting part, and i don't know how to insert a code into another code in SQL.
I’ve tried GROUP BY (for the first time) and I didn’t make it.
in fact, after a few days of failed attempts, i started thinking if my data structure is the real problem...
thank you for your help and your attention.
Using a group by is a good idea, but you might want to add a count of catergories to help you to sort.
In example :
Schema (MySQL v5.7)
CREATE TABLE book (
`title` VARCHAR(10),
`id` VARCHAR(3) PRIMARY KEY
);
INSERT INTO book
(`title`, `id`)
VALUES
('Nightmare', 'AAA'),
('Wonderful.', 'AAB'),
('GhostNight', 'AAC'),
('Babysitter', 'AAD'),
('Helloworld', 'AAE'),
('Hannibal', 'AAF');
CREATE TABLE cat (
`BookID` VARCHAR(3),
`Description` VARCHAR(50),
`Relevance` VARCHAR(7),
FOREIGN KEY (`BookID`) REFERENCES book (id)
);
INSERT INTO cat
(`BookID`, `Description`, `Relevance`)
VALUES
('AAA', 'Thriller', '0'),
('AAA', 'Crime', '0'),
('AAA', 'Detective', '0'),
('AAB', 'Geography', '0'),
('AAB', 'Travel', '0'),
('AAC', 'Thriller', '0'),
('AAD', 'Comedy', '0'),
('AAD', 'Family', '0'),
('AAE', 'Programming', '0'),
('AAE', 'Computer Science', '0'),
('AAF', 'Thriller', '0'),
('AAF', 'Crime', '0');
Query #1
SELECT b.title, COUNT(c.description) AS cnt
FROM book b
LEFT JOIN cat c
ON b.id = c.BookID
WHERE c.Description IN ('Thriller', 'Crime')
GROUP BY b.title
ORDER BY cnt DESC;
Output
| title | cnt |
| ---------- | --- |
| Nightmare | 2 |
| Hannibal | 2 |
| GhostNight | 1 |
View on DB Fiddle
Related
I am working on an online university that has users, courses, and user to course status. I have a list of users, and another list of courses. I want to find the course status for all of the given users and courses, including null status for a course that a user hasn't yet started.
So for example:
User IDs: [1, 7, 14, 21]
Course IDs: [5, 8, 36, 50]
Desired result:
Name Course Status
John Doe How to Tie your Shoes Complete
John Doe How to Paint your House In Progress
Jane Doe How to Tie your Shoes Complete
Jane Doe How to Paint your House Not Started <-- These are the tricky ones
...
It seems that I can perform a LEFT JOIN on the tables and get some NULL values, which I can coalesce into 'Not Started' but as soon as I add some constraints to limit which courses and/or users I'm looking for...it stops giving me NULL values values because a NULL course ID clearly isn't in my list of courses above.
Here's an example query giving you an idea of what I've been trying (among other things):
SELECT
`users`.`name` AS `Name`,
`users`.`email` AS `Email`,
`courses`.`number` AS `Course #`,
`courses`.`name` AS `Course`,
COALESCE(`courses_users_statuses`.`name`, 'Not Started') AS `Status`
FROM
`users`
LEFT JOIN `courses_users`
ON `courses_users`.`user_id` = `users`.`id`
LEFT JOIN `courses`
ON `courses`.`id` = `courses_users`.`course_id`
LEFT JOIN `courses_users_statuses`
ON `courses_users_statuses`.`id` = `courses_users`.`status_id`
WHERE
`courses`.`id` IN ([1, 2, 3, 4, 5, 10, 11, 12, 16, ...])
AND `users`.`id` IN ([1, 2, 3, 4, 5, 20, 21, 36, 48, ...])
ORDER BY
`users`.`name`,
`courses`.`number`
Any ideas on how to write something like this? Also, let me know if I can provide any more detail or more code/table examples.
EDIT: Here's my updated query using advice from the answers below:
SELECT
`users`.`name` AS `Name`,
`users`.`email` AS `Email`,
`courses`.`number` AS `Course #`,
`courses`.`name` AS `Course`,
COALESCE(`courses_users_statuses`.`name`, 'Not Started') AS `Status`
FROM
`users`
LEFT JOIN
`courses_users` ON `courses_users`.`user_id` = `users`.`id`
LEFT JOIN
`courses` ON `courses`.`id` = `courses_users`.`course_id` AND `courses`.`id` IN (1, 2, 3, 4, 5)
LEFT JOIN
`courses_users_statuses` ON `courses_users_statuses`.`id` = `courses_users`.`status_id`
WHERE
`users`.`id` IN (1, 2, 3, 4, 5)
ORDER BY
`partners`.`name`,
`users`.`name`,
`courses`.`number`
This updated example is an improvement, but now it's showing records where there is no course name or number, but there IS a status. I'm not sure how it's grabbing a status for course relations that should exist. Instead those should be NULL (or "Not Started"). Here's some sample data from the database:
`users` table:
id name email
1 Stevie McComb test#example.com
2 John Doe test#example.org
3 Jane Doe test#example.net
`courses` table:
id number name
1 101 Navigation
2 102 Logging In
3 103 Updating Records
4 104 Managing Users
`courses_users` table:
course_id user_id status_id completed_at
1 1 2 2017-01-01 00:00:00
3 1 1 2017-01-05 00:23:00
1 2 2 2017-04-13 15:00:37
`courses_users_statuses` table:
id name slug
1 In Progress progress
2 Complete complete
Desired Result:
Name Email Course # Course Status
Stevie McComb test#example.com 101 Navigation Complete
Stevie McComb test#example.com 102 Logging In Not Started
Stevie McComb test#example.com 103 Updating Records In Progress
Stevie McComb test#example.com 104 Managing Users Not Started
John Doe test#example.org 101 Navigation Complete
John Doe test#example.org 102 Logging In Not Started
John Doe test#example.org 103 Updating Records Not Started
John Doe test#example.org 104 Managing Users Not Started
Jane Doe test#example.net 101 Navigation Not Started
Jane Doe test#example.net 102 Logging In Not Started
Jane Doe test#example.net 103 Updating Records Not Started
Jane Doe test#example.net 104 Managing Users Not Started
Current Result:
Name Email Course # Course Status
Stevie McComb test#example.com Complete
Stevie McComb test#example.com Not Started
Stevie McComb test#example.com 103 Updating Records In Progress
Stevie McComb test#example.com Not Started
John Doe test#example.org 101 Navigation Complete
John Doe test#example.org Not Started
John Doe test#example.org Not Started
John Doe test#example.org Not Started
Jane Doe test#example.net Not Started
Jane Doe test#example.net Not Started
Jane Doe test#example.net Not Started
Jane Doe test#example.net Not Started
The problem is that you're putting the constraints in your where clause, without allowing for a null value.. This essentially changes the left join back to an inner join.
To fix this, you can either explicitly allow for nulls, or you can move the logic to the join clause (my preference).
select
`users`.`name` as `name`,
`users`.`email` as `email`,
`courses`.`number` as `course #`,
`courses`.`name` as `course`,
coalesce(`courses_users_statuses`.`name`, 'not started') as `status`
from
`users`
left join `courses_users`
on `courses_users`.`user_id` = `users`.`id`
left join `courses`
on `courses`.`id` = `courses_users`.`course_id`
and `courses`.`id` in ([1, 2, 3, 4, 5, 10, 11, 12, 16, ...])
left join `courses_users_statuses`
on `courses_users_statuses`.`id` = `courses_users`.`status_id`
where
`users`.`id` in ([1, 2, 3, 4, 5, 20, 21, 36, 48, ...])
order by
`users`.`name`,
`courses`.`number`
When I have to deal with potentially NULL values, I use
IFNULL(field_name, 'use this value instead');
For instance
SELECT
IFNULL(Course, 'Nothing Found') AS course
FROM
Course
Where....
Or you could specify in your WHERE clause...
WHERE Course IS NOT NULL
I'm fairly new to sql and am trying to get data from table X when the user is not in table Y with the combination of player id and world id AND the player access is 2.
Let me explain a little furter:
Table X (user table)
+-----------+----------+------------+
| uid | access | more data |
+-----------+----------+------------+
| 1 | 2 | .... |
| 2 | 1 | .... |
| 3 | 2 | .... |
+-----------+----------+------------+
Table Y (worlds)
+-----------+-----------+
| userUuid | worldUuid |
+-----------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
+-----------+-----------+
When I want to get all users which I can still add to world 1 I want to get the user info from user 3.
User 1 already is in world 1, user 2 does not have access level 2 and user 3 isn't in world 1 yet and does have access level 2.
I'm using medoo and this is my statement at the moment:
$database->select("User", [
"[>]UserInWorld" => ["uid" => "userUid"]
], [
"uid",
"displayname",
"surname",
"email"
], [
"AND" => [
"worldUuid[!]" => $worldUuid,
"access" => 2
]
]);
The worldUuid will be the world I want to get user to add for.
When use the ->debug() the query looks like this:
SELECT "uid","displayname","surname","email"
FROM "User"
LEFT JOIN "UserInWorld" ON "User"."uid" = "UserInWorld"."userUid"
WHERE "worldUuid" != '4dafb8c0-57234ff2-03eb-af7f7a5e'
AND "access" = 2
EDIT: I posted a sollution using medoo below
If I understand you correctly, you should be able to do something like this:
SELECT
uid,
displayname,
surname,
email
FROM
User
LEFT JOIN UserInWorld ON User.uid = UserInWorld.userUid AND worldUuid = 1
INNER JOIN (
SELECT DISTINCT
userUid
from
UserInWorld
WHERE
worldUuid != 1
) AS InOtherWorld ON InOtherWorld.userUid = User.uid
WHERE
access = 2
AND UserInWorld.userUid IS NULL
The left join will connect people in the world where possible and then UserInWorld.userUid IS NULL will effectively strip it down to those that aren't in the world.
you said:
am trying to get data from table X when the user is not in table Y with the combination of player id and world id AND the player access is 2
If I've understood it should be:
select * from X where X.access = 2 and X.uid not in (
select Y.userUuid from Y
)
After a good night sleep I figured out how to do this using the medoo class
$database->select("User", [
"[>]UserInWorld" => ["uid" => "userUid"]
], [
"uid",
"displayname",
"surname",
"email"
], [
"AND" => [
"OR" => [
"worldUuid[!]" => [$worldUuid],
"worldUuid" => NULL
],
"access" => 2
],
"GROUP" => "uid"
]);
Whereby the $worldUuid the world is I want to select users for.
This will make the following sql statement:
SELECT "uid","displayname","surname","email" FROM "User"
LEFT JOIN "UserInWorld" ON "User"."uid" = "UserInWorld"."userUid"
WHERE ("worldUuid" NOT IN ('1') OR "worldUuid" IS NULL)
AND "access" = 2
GROUP BY "uid"
This will select all (unique) user who do not have a world already OR are in the world I'm getting users for AND they have access level 2
I have a table called Grades and inside I have some columns:
Id id_student Subjects grade
3 1 [->] Biology 8
4 1 [->] Math 4
5 1 [->] Sports 4
6 1 [->] Math 8
7 1 [->] English 9
8 4 [->] Sports 10
9 4 [->] English 7
I selected everything from this table where id_student = student logged in
$sth = $this->dbh->prepare("SELECT * FROM note WHERE id_elev = :id_elev");
$sth->bindParam(":id_elev", $_SESSION['id']);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_ASSOC);
So all I selected is this:
Id id_student Subjects grade
3 1 [->] Biology 8
4 1 [->] Math 4
5 1 [->] Sports 4
6 1 [->] Math 8
7 1 [->] English 9
I want to make a average grade for Math , Biology , etc for this student but I want it without making a SELECT * FROM Grades WHERE $result['Subjects'] == 'Biology' because some students may not have this subject in their schedule.
I want something like this:
Id id_student Subjects grade
4 1 [->] Math 4
6 1 [->] Math 8
But without WHERE $results['Subjects'] == 'Math';
I'm sorry it is hard to explain when you don't know a lot of english. I hope that someone understands what I wrote and give me an advice. I can make another table called Subject if it is necessary.
Check out this fiddle:
http://sqlfiddle.com/#!2/8ee5a/3
I think it does what you need. If not, it's a great place to test the query.
I used the GROUP BY function AVG() to get the average grade for each subject.
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_avg
Here is the schema and query:
CREATE TABLE grades
(
Id int auto_increment primary key,
id_student int,
Subjects varchar(20),
grade int(1)
);
INSERT INTO grades
(Id, id_student, Subjects, grade)
VALUES
('3', '1', 'Biology', 8),
('4', '1', 'Math', 4),
('5', '1', 'Sports', 4),
('6', '1', 'Math', 8),
('7', '1', 'English', 9);
SELECT id_student, Subjects, AVG(grade) FROM grades GROUP BY Subjects;
The query below is an example of the use I mentioned in my comment
-- The AVG() function returns the average value of a numeric column.
-- because you are executing an aggregate function on the Grade column you have to specify which columns to group the results together by.
SELECT
Id
,Subject
,AVG(Grade) as 'Average Grade'
FROM
Result
GROUP BY
Id
,Subject
I wish to select all records from a database and then combine matching keys and also adding their values.
Col1 col2
----- ------
ABC 2
ABA 3
ADD 1
AED 3
ABC 2
ABA 3
ADD 1
AED 3
So i would end up with
array("
ABC => 4,
ABA => 6,
ADD => 2,
AED => 6");
This is basic GROUP BY application:
SELECT Col1, SUM(col2) FROM tbl GROUP BY Col1
See http://sqlfiddle.com/#!2/8d1f8/1 for an example
I am building some sort of a CMS in PHP and i ran into an issue, hoping you guys can help me out with it.
I'll post an example of what my database looks like and what i need to be done.
ID | Name | Order
1 | A1 | 1
2 | A2 | 3
3 | A3 | 4
4 | A4 | 2
What i need is a way to edit the 'order' column of DB dynamically, as in if i was to change the order of 'A2' to '2', it will automatically change the order of 'A4' which was originally '2' and update it to whatever order 'A2' was, which is '3'
If this wasn't clear enough, i would be more than happy to screen shot my database to clarify it more.
Thanks in advance
change the order of 'A2' to '2', it will automatically change the
order of 'A4' which was originally '2' and update it to whatever order
'A2' was, which is '3'
UPDATE Orders SET `Order` = (SELECT `Order` FROM Orders WHERE id = 2) WHERE `Order` = 4;
UPDATE Orders SET `Order` = 3 WHERE id = 2;