Is there a way where in I could use the sub_name, instead of the sub_id?
This is my code..
echo "<table border=1 align=center><tr class=style2><td>Date<td>Student Name <td> Subject <td> Score";
$sortQuery = mysql_query("select * from mst_adminresult",$cn) or die(mysql_error());
while($row=mysql_fetch_row($sortQuery))
{
echo "<tr class=style8><td>$row[5]<td>$row[1] <td align=center> $row[4] <td align=center> $row[3]/20";
}
echo "</table>";
this code shows a result of all the exam taken. In the Subject it's output is the subject ID. I'm just wondering if there is any way I could get its subject name. The subject name is in different table.
adminresult_tbl
CREATE TABLE `mst_adminresult` (
`adminResultID` int(5) NOT NULL,
`login` varchar(20) NOT NULL,
`test_id` varchar(20) NOT NULL,
`score` int(3) NOT NULL,
`test_date` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
subjecet_tbl
CREATE TABLE `mst_subject` (
`sub_id` int(5) NOT NULL,
`sub_name` varchar(25) DEFAULT NULL,
`sub_desc` text
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
test_tbl
CREATE TABLE `mst_test` (
`test_id` int(5) NOT NULL,
`sub_id` int(5) DEFAULT NULL,
`test_name` varchar(30) DEFAULT NULL,
`total_que` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The flow of the program is, when the user takes an exam, the user will be redirected to a page where all the subjects are listed, then the user will choose the subject she wants to take, after that, a list of tests will show, then the user will choose again and that's when the user can have the quiz.
In the list of subjects, I've called the subject_tbl. In the list of test, the test_tbl. When the user is finished taking the exam, it will store in the adminresult_tbl
JOIN the 3 tables. Try this:
SELECT * FROM mst_adminresult m
JOIN test_tbl t ON t.test_id = m.test_id
JOIN subject_tbl s ON s.sub_id = t.sub_id;
As depicted by #PrinceG, you may use the JOIN syntax to read values from other tables. To stay in the format of your coding, the SQL statement should read something like this:
SELECT ar.*, s.sub_name
FROM mst_adminresult AS ar
LEFT JOIN mst_test AS t ON t.test_id = ar.test_id
LEFT JOIN mst_subject AS s ON s.sub_id = t.sub_id;
Doing so will allow you to access the subject's name via $row[6].
However, also note that your database modelling is quite risky to do so:
You did not specify any primary key on your master data (e.g. mst_subject and mst_test) tables. This may lead to severe data inconsistencies if not handled carefully. Introducing primary keys are a very good habit for good reasons - for example see http://www.mysqltutorial.org/mysql-primary-key/
There is not referential integrity set up for your tables, although the underlying DB engine InnoDB supports it. Thus, it may happen - for instance - that you have a test_id of 5 in mst_adminresult, which does not have a corresponding record in mst_test. As the statement above uses LEFT JOINs, this would not suppress your record in the resultset returned, but a NULL value would show up in PHP. However, I doubt that this is intentional in your case. Instead, I would assume that it was a better approach that the DB would raise an error already when inserting a record into mst_adminresult for which no test is provided so far in mst_test.
The same pattern also applies to mst_subject in regards to mst_test.
In sum, you may find articles like that one on ER Modeling interesting.
Related
(Spoiler: The Title has nothing to do with what is wrong with the code.)
I'm creating a live-search system just to show the user possible event types already listed on my website. During my speculations I may have an error with Wildcard binding which I'm unable to see.
I tried using different types of "WHERE LIKE" statements, and most of them didn't work at all. Such as I tried using placeholder query (question mark) and that did not work at all. If I ran this query manually on my database I will get results which I'm expecting.
This is how my code looks, the variable $q is obtained using $_GET method.
$query = $pdo->prepare('SELECT DISTINCT EventCategory FROM Events
WHERE EventCategory LIKE CONCAT(\'%\',:q,\'%\')');
$query->bindParam(":q", $q);
$query->execute();
$row = $query->fetch(PDO::FETCH_ASSOC);
while ($row = $query->fetchObject()) {
echo "<div> $row->EventCategory </div>";
}
The expected results would be: If the $q is equal to n, Meeting and Nightlife is returned. When $q is equal to ni, then Nightlife is only returned.
The search is NOT CASE SENSITIVE, N and n is treated equally.
The SHOW CREATE TABLE Events query returned the following:
CREATE TABLE `Events` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(100) NOT NULL,
`Image` varchar(600) NOT NULL,
`Date` date NOT NULL,
`Description` varchar(1200) NOT NULL,
`SpacesAvailable` int(11) NOT NULL,
`EventCategory` varchar(50) NOT NULL,
`Trending` varchar(30) DEFAULT NULL,
`TrendingID` int(255) NOT NULL,
`Sale` int(255) NOT NULL,
PRIMARY KEY (`ID`)
)DEFAULT CHARSET=latin1
Images to show the operation of the website: https://imgur.com/a/yP0hTm3
Please if you are viewing the images the view from bottom to top. Thanks
I suspect the default collation in your EventCategory column is case-sensitive. That's why Ni and ni don't match in Nightlife.
Try this query instead.
'SELECT DISTINCT EventCategory FROM Events WHERE EventCategory COLLATE utf8_general_ci LIKE CONCAT(\'%\',:q,\'%\')'
Or, if your column's character set is not unicode but rather iso8859-1, try this:
'SELECT DISTINCT EventCategory FROM Events WHERE EventCategory COLLATE latin1_general_ci LIKE CONCAT(\'%\',:q,\'%\')'
This explains how to look up the available character sets and collations on MySQL.
How to change collation of database, table, column? explains how to alter the default collation of a table or a column. It's generally a good idea because collations are baked into indexes.
The problem is not in LIKE, but in PHP and PDO. Stare at the 3 conflicting uses of $row in your code:
$row = $query->fetch(PDO::FETCH_ASSOC);
while ($row = $query->fetchObject()) {
echo "<div> $row->EventCategory </div>"; }
Then review the documentation and examples. (Sorry, I'm not going to feed you the answer; you need to study to understand it.)
In complement to the comprehensive answer by O.Jones, another, simpler solution would be to just perform a case-insensitive search, like :
'SELECT DISTINCT EventCategory
FROM Events
WHERE UPPER(EventCategory) LIKE CONCAT(\'%\',UPPER(:q),\'%\')'
I have two tables as below
table halte :
CREATE TABLE `halte` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nama` varchar(255) NOT NULL,
`lat` float(10,6) DEFAULT NULL,
`lng` float(10,6) DEFAULT NULL,
PRIMARY KEY (`id`)
)
table stops :
CREATE TABLE `stops` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_halte` int(11) DEFAULT NULL,
`sequence` int(2) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_halte` (`id_halte`)
)
I also have some other tables which don't cause any problems.
Halte table has many to one relation to stop. The problem is when i try to get rows from halte table using right join to table stops, Yii only returns unique rows. Yii won't return same halte's row more once even stop table has more than one record related to same row in halte table.
Here's my code
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
I have tried distinct(false) but no result.
I've also check debugger and it run right query i want :
SELECT `halte`.* FROM `halte` RIGHT JOIN `stops` ON halte.id = stops.id_halte WHERE `stops`.`id_rute`='1' ORDER BY `sequence`
I tried to run that query manually and it returned 29 rows which is what what i want. But in Yii, it only returned 27 rows because 2 rows is same record in halte table.
I know i can achieve this using yii\db\Query, but i want to use ActiveRecord.
Are there any way to work around this?
I would really appreciate your opinion/help.
Thanks.
Check the sql command generated by you active query
$haltes = $modelHalte->find()
->rightJoin('stops', 'halte.id = stops.id_halte')
->where(['stops.id_rute'=>Yii::$app->request->get('rute')])
->orderBy('sequence')
->all();
echo $haltes->createCommand()->sql;
or to get the SQL with all parameters included try:
$haltes->createCommand()->getRawSql();
And compare the code generated by ActiveQuery with your created manually ..
If I log in with my email and password in table 'students', how can I get the data from the table 'data' where the emailadresses match?
CREATE TABLE `students` (
`email` varchar(150) NOT NULL,
`password` varchar(150) NOT NULL
)
CREATE TABLE `data` (
`student_id` varchar(50) NOT NULL,
`studygroup_id` varchar(50) NOT NULL,
`applied_courses` varchar(50) NOT NULL,
`study_results` varchar(50) NOT NULL,
`email` varchar(150) NOT NULL
)
Well, the easy answer would just be to execute a query like
SELECT * FROM data WHERE email = '$emailAddress'
Where $emailAddress is the email address that has been used to log in.
But you should really think about your schema design. Perhaps go and read some books/tutorials on the basics and there are a number of possible issues with what you have. You should probably have a numeric primary key on your "students" table and reference this as a foreign key in your other table. You should also think about renaming the second table. "Data" doesn't really describe what it does; everything (or very nearly) in a database is data! Plus all your id columns are varchars. Unless you have alphanumeric ids you should make these columns the correct type for the data they hold.
Please clarify question. Where's the password coming from? A script in PHP?
SELECT * FROM data WHERE student.email = "$my_email" AND student.password = "$my_password"
Students table should also contain the student_id
alter table student add column student_id int auto_increment primary key
then the query
select a.email, a.password,b.studentgroup_id, b.applied_course,b.student_result
from student a inner join
data b
on a.student_id=b.student_id
If you want to confirm login and get data in one query, use a LEFT JOIN, which in the following example will give you a result from the students table, even if there is nothing in the data table for that email address.
$query = "SELECT * FROM `students`
LEFT JOIN `data` ON `students`.`email` = `data`.`email`
WHERE `students`.`password` = '" . $password . "'
AND `students`.`email` = '" . $email. "'";
Note: if there are multiple rows in the data table for the email address, each row will be returned and will contain identical student.password and student.email values.
I have created this database schema and with help from several users on here, I have a database which takes user submitted business entries stored in the business table, which are additionally grouped under one or several of about 10 catagories from the catagories table, in the tbl_works_catagories table by matching the bus_id to the catagory id.
For example, bus_id 21 could be associated with catagory_id 1, 2, 5, 7, 8.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL
)
Now, what i want to do next is a search function which will return businesses based on the catagory. For example, say one of the businesses entered into the business table is a bakers and when it was entered, it was catagorised under Food (catagory_id 1) and take-away (catagory_id 2).
So a visitor searches for businesses listed under the Food catagory, and is returned our friendly neighbourhood baker.
As with all PHP/MySQL, i just can't (initially anyway) get my head around the logic, never mind the code!
You should setup foreign keys in your tables to link them together.
CREATE TABLE `business` (
`bus_id` INT NOT NULL AUTO_INCREMENT,
`bus_name` VARCHAR(50) NOT NULL,
`bus_dscpn` TEXT NOT NULL,
`bus_url` VARCHAR(255) NOT NULL,
PRIMARY KEY (`bus_id`)
)
CREATE TABLE `categories` (
`category_id` INT NOT NULL AUTO_INCREMENT,
`category_name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`category_id`)
)
CREATE TABLE `tbl_works_categories` (
`bus_id` INT NOT NULL,
`category_id` INT NOT NULL,
FOREIGN KEY (`bus_id`) REFERENCES business(`bus_id`),
FOREIGN KEY (`category_id`) REFERENCES categories(`category_id`)
)
Then your search query would be something like:
SELECT b.*
FROM business b, categories c, tbl_works_categories t
WHERE
b.bus_id = t.bus_id AND
c.category_id = t.category_id AND
c.category_id = *SOME SEARCH VALUE*
which using JOIN would be written as:
SELECT b.*
FROM business b
JOIN tbl_works_categories t
ON b.bus_id = t.bus_id
JOIN categories c
ON c.category_id = t.category_id
WHERE c.category_id = *SOME SEARCH VALUE*
Maybe you want something like this:
SELECT `bus_id` FROM `tbl_works_categories` WHERE `category_id` = *some id from the search*
AND `category_id` = *some other id from the search*;
Although you'd need those ids- there are a few ways to do this, I'll describe probably the most straight forward...
You get categories from $_POST, so let's just say you have 2 of them entered. (Food, and take-away). Parse these however you want, there are multiple ways, but the point is they're coming from $_POST.
execute this sort of thing for each one you find:
SELECT `category_id` FROM `categories` WHERE `category_name` LIKE '%*the name from $_POST*%';
Store these results in an array...based on how many you have there you can build an applicable query similar to the one I describe first. (Keep in mind you don't need and AND there, that's something you have to detect if you return > 1 category_id from the second query here)
I'm not going over things like security..always be careful when executing queries that contain user submitted data.
An alternate solution might involve a join, not too sure what that'd look like off the top of my head.
Good luck.
If you want all businesses that are related to the given category-id, your SQL-statement would look something like this:
SELECT `business`.`bus_name`
FROM `business`
WHERE `business`.`bus_id` = `tbl_works_categories`.`bus_id`
AND `categories`.`category_id` = `tbl_works_categories`.`category_id`
AND `categories`.`category_id` = 1;
Where 1 in this case is your food-category, but could be your PHP variable where the ID of the category the user selected is stored.
And one hint: Be sure to name your tables either in plurar or in singular. You are mixing both and could get confused.
I've two tables let's say booking and supplier
Fetching the records from both tables with-in date-range as follow
$query = "SELECT booking.book_id AS Id,
booking.referance_no AS RefNo,
booking.entry_date AS DepDate,
booking.name AS Name,
booking.mobile AS mobile,
booking.comp_title AS Company
FROM booking WHERE active='1' $WHERE1
GROUP BY booking.book_id
UNION ALL
SELECT supplier.id AS Id,
supplier.reference_no AS RefNo,
supplier.departure_date_time AS DepDate,
supplier.name AS Name,
supplier.mobile AS Mobile,
supplier.company AS Company
FROM supplier WHERE active='1' $WHERE2
ORDER BY `DepDate` DESC LIMIT 1000";
Note: I remove lots of code lines as they are not relevant to this question so as $WHERE1 and $WHERE2, they are just date range clause.
After query fetching data (while loop) to HTML table
<td><?php echo $row['RefNo'];?></td>
<td><?php echo $row['Name'];?></td>
<td><?php echo $row['Mobile'];?></td>
<td><?php echo $row['DepDate'];?></td>
<td><?php echo $row['Company'];?></td>
<td><a class="btn" href="delete.php?RefNo=<?php echo $row['RefNo'];?>">Delete</a></td>
In HTML view, I know that <?php echo $row['RefNo'];?> in href belongs to which table booking Or supplier but PHP doesn't know it and on delete.php I've to call both tables and first have to check the RefNo against each table and then if it's true delete the record
delete.php
$ReferenceNo = $_GET['RefNo'];
//Fetch records from both tables
//Check records against `$ReferenceNo`
//If true against `booking` table
"Delete From booking where referance_no=$ReferenceNo"
//else
"Delete From supplier where reference_no=$ReferenceNo"
The question, is there better approach to delete the record where I don't have to call both tables and first check RefNo against each table.
Edit to make Question more clear:
As I mentioned somewhere above that PHP doesn't know <?php echo $row['RefNo'];?> belongs to which table booking or supplier so I need the work around where before any action (Delete, Cancel, Edit) I can tell PHP that <?php echo $row['RefNo'];?> belongs to this table booking or supplier so no need to check <?php echo $row['RefNo'];?> against both tables before any action Delete, Cancel, Edit
Each row in html table has something like:
<input type="hidden" name="myIncrNNN" value="tableX">
that is not visible, and picked up to clue you in to what to do upon processing.
Edit: to make it more clear
your
<td><a class="btn" href="delete.php?RefNo=<?php echo $row['RefNo'];?>">Delete</a></td>
Would be altered to pick up the hidden column clue.
Yours now would be an ultimate call to :
http://example.com/somedir/delete.php?RefNo=7
in my imaginary world it would become
http://example.com/somedir/delete.php?RefNo=7&tc=1
Where tc means table clue from the hidden input field
Does not require a schema change, and added table, and is obvious that the client is telling the server what to do, no more or less than the original in the face of it all, and does not say the client is an Authority of anything, like #Halcyon is suggesting.
Edit 2: (to show UNION chg)
$query = "SELECT booking.book_id AS Id,
booking.referance_no AS RefNo,
booking.entry_date AS DepDate,
booking.name AS Name,
booking.mobile AS mobile,
booking.comp_title AS Company,
'booking' as TableClue -- <------ RIGHT THERE
FROM booking WHERE active='1' $WHERE1
GROUP BY booking.book_id
UNION ALL
SELECT supplier.id AS Id,
supplier.reference_no AS RefNo,
supplier.departure_date_time AS DepDate,
supplier.name AS Name,
supplier.mobile AS Mobile,
supplier.company AS Company,
'supplier' as TableClue -- <------ RIGHT THERE
FROM supplier WHERE active='1' $WHERE2
ORDER BY `DepDate` DESC LIMIT 1000";
You're dealing with non-normalized data. In essence you have two tables that contain the same data (more or less). To normalize you have to add a table that maps reference_no to entries in booking and supplier. You can query that table to see which record to delete or go the full mile set up a foreign-key cascade.
Something like this:
CREATE TABLE `booking` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`reference_no` int(11) NOT NULL,
`etc` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `supplier` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`reference_no` int(11) NOT NULL,
`etc` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `reference_no` (
`reference_no` int(11) NOT NULL,
`booking` int(11) DEFAULT NULL,
`supplier` int(11) DEFAULT NULL,
KEY `booking` (`booking`),
KEY `supplier` (`supplier`),
CONSTRAINT `reference_no_ibfk_4` FOREIGN KEY (`booking`) REFERENCES `booking` (`id`) ON DELETE CASCADE,
CONSTRAINT `reference_no_ibfk_5` FOREIGN KEY (`supplier`) REFERENCES `supplier` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
In practise though, you probably don't have to do this. Delete on both tables seems fine to me.
first have to check the RefNo against each table and then if it's true delete the record
No you don't. Just issue the DELETE statements:
DELETE FROM booking WHERE referance_no=$ReferenceNo
DELETE FROM supplier WHERE reference_no=$ReferenceNo
If no matching records exist when a DELETE statement executes then no records will be deleted. The default behavior is what you want... delete matching records if they exist.