So I'm working on an assignment right now and I can't wrap my head around the logic.
I have to populate an HTML select box with a list of courses based on a qualification code where the user is not already enrolled in a course.
Here is my current code:
//Get logged in users id
$currentID = getIDForUser($_SESSION['username']);
//Get logged in users qualification code
$qualificationCode = getUserQualification($currentID);
//Get and display list of avaliable courses for qualificationCode
$query = mysql_query("");
while($row = mysql_fetch_array($query)) {
$courseName = $row['courseName'];
$courseCode = $row['courseCode'];
print("<option value='$courseCode'>$courseName</option>");
}
The layout of the database is as follows
Courses table:
Courseoccurrence table:
So, basically at this stage the combo box will populate with Multimedia & Design as well as Data Structures & Algorithms. However, if I select Multimedia and enroll in it, it will not populate the box with that course anymore.
Stop using mysql_*, it's deprecated. Go with mysqli_* or PDO instead.
Not absolutely necessary, but you might want to change your collation from latin1_swedish_ci to utf8_general_ci or you will face problems if you ever decide to put special characters in your DB.
Now, to actually address your question:
In your question you don't say what your problem is, specifically, but based on the title I assume that you know how to build everything except for the SELECT query.
So, first you want to select all the courses that the current user is enrolled in. Then, based on the result, you want to fetch all courses that are not in the list you just selected.
This can be done fairly easily with a subselect:
// Assuming $mysqli is an OOP database handle
$query = $mysqli->prepare('SELECT `courseName`, `courseCode` FROM `Courses` WHERE `courseCode` NOT IN (SELECT `courseCode` FROM `Courseoccurrence` WHERE `personID` = ?)');
$query->bind_param('i', $currentID);
$result = $query->get_result();
while($row = $result->fetch_array())
// ...
SQL Explanation:
I think SELECT, FROM, WHERE and NOT require no explanation.
IN checks whether a value is in a list like 'A' IN ('A', 'B', 'C').
And (SELECT ...) is a so-called subselect (see Subqueries), which is a simple SELECT whose result you can use in your query, and in case of it having only one column (because we only select courseCode), it can be used as an argument to IN.
Related
I want to show recommended users to a user in descending order where skills match the most.
Issue is that I am storing skill in single field in this form
user_skill
musician,pop,singer
Note: this will be input musician,pop,singer..
so what I want to achieve I want to show users have all three skills at top,then those having two at last those having only one.
so out put will be like
**user_name skills**
sam musician,pop,singer
smith musician,pop,singer
ali musician,singer
nasira musicain,pop
siri musician
taylor pop
andrew singer
Can this be achieved by single mysql query?
If this not possible can this be done by php code.I don't want to change table structure as this will require lots of redo.
Thanks for your help.
You might be able to do with with SQL but the query would be so complex i probably wouldnt.
On the php side you could iterate over the result set and tally the skills for each user_name within a given set of skills you are looking for, and then just sort them:
$desired = explode(',', $input);
$users = array();
// i presume you have the query worked out to find users with any one of input
// skills attributed to them so lets say that $stmt is the PDO statement where you
// have executed that query
while (false === ($row = $stmt->fetch(PDO::FETCH_ASSOC))) {
$row['skills'] = explode(',', $row['skills']);
// assign an array containing only skills that were in your $input
// to $row['desired_skills']
$row['desired_skills'] = array_intersect($desired, $row['skills']);
$row['nb_desired_skills'] = count($row['desired_skills']);
$user[] = $row;
}
usort($users, function ($a, $b) {
return $b['nb_desired_skills'] - $a['nb_desired_skills'];
});
// now you can loop over $users and display the fields you need
However, the definition and attribution of these skills is a key part of you application, you should just normalize the tables now... its only going to become a larger refactor by putting it off.
I don't want to change table structure as this will require lots of redo.
I strongly (!) recommend you make a separate skills table, and link that to your users table using foreign keys. You will be infinitely thankful to yourself once your project gets even slightly more complex.
If you don't know how, I'm sure people on this site would help you with a script that does the conversion if you were to post another question.
MySQL
CREATE TABLE skills
(
name VARCHAR(64) NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY (name, user_id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
This way you can easily select users by most skills using a simple subquery (assuming you have a users table with an id column):
MySQL
SELECT *,
(SELECT COUNT(*)
FROM skills
WHERE user_id = u.id) AS num_skills
FROM users u
ORDER BY num_skills DESC;
So why would you take this approach instead of relying on PHP?
Creates minimal extra overhead in database,
significantly reduces chatter between database and webserver by not requiring to query the entire users table if you just want, for example, only the top 10 users,
enables more complex and varying queries in the future easily.
The following MySQL snippet queries only those users who have a given skill (for example, "singer"), then sorts them in descdending order based on number of skills. The query does not return users with zero skills:
MySQL
SELECT *,
(SELECT COUNT(*)
FROM skills
WHERE user_id = u.id
AND name = 'singer') AS num_skills
FROM users u
WHERE num_skills > 0
ORDER BY num_skills DESC;
Of course, you can also search for skills by id just replace the second part of the WHERE clause inside the subquery with AND id = 3, which will query those users, who have a skill with ID of 3.
The next step towards a more optimal database would be creating a real skills table, which stores only the skills that you have registered in your database, and a user_skills table, that links it and the users table together.
This would enable you to significantly reduce database size on the long run, and be able to run complex but 'clean' queries that do not depend on the webserver.
I have 2 tables, a users table and a trade table.
Which look like:
The structure of my code right now is:
<?php
$history = mysqli_query($con, "SELECT * FROM .......");
while($row = mysqli_fetch_array($history)) {
echo("The sentence");
} ?>
Problem I'm facing is that I'm trying to echo the user_name which in one case has to be the receiver and other the person giving it.
Pro tip: Never use SELECT * in software unless you know exactly why you are doing so. In your case it is harmful.
I'm assuming your query is really against the user and trade tables you mentioned in your question.
First, recast your query using 21st century SQL, as follows:
SELECT *
FROM trade AS t
JOIN user AS s ON s.user_id = t.user_id_sender
WHERE s.facebook_id = $fbid
Second, use this to retrieve your user's names and the item id traded.
SELECT s.user_name AS sender,
r.user_name AS receiver,
t.trade_id AS item_id
FROM trade AS t
JOIN user AS s ON s.user_id = t.user_id_sender
JOIN user AS r ON r.user_id = t.user_id_receiver
WHERE s.facebook_id = $fbid
See how we JOIN the user table twice, with two different aliases s (for sender) and r (for receiver)? That's the trick to fetching both names from IDs.
See how we employ the aliases sender and receiver to disambiguate the two user_name columns in the result set?
Now, when you use the php fetch_array function, you'll end up with these elements in the array.
$history['sender']
$history['receiver']
$history['item_id']
The array index strings correspond to the alias names you specified in your SELECT clause in your query.
So, one reason to avoid SELECT * is that you can get more than one column with the same name, and that means fetch_array will eliminate those duplicates and so it will lose useful information from your result set.
I develope a website for E-books, i have in database table for authors and table for publishers .. sometimes the author name is added also in publishers table as a publisher
Now i have his name as an author and a publisher .. when i search in the site for his name, it return twice because i search in authors table and in publishers table then merge two queries
this is my code :-
function generate_results($keyword, $row = 0) {
$result1 = $this->db->query("SELECT au_id,au_name,au_state,SUBSTR(au_info,1,190) AS au_info,au_img FROM d_author where (au_name LIKE '%$keyword%' or au_info LIKE '%$keyword%') and au_state = '1' limit $row,20");
$result2 = $this->db->query("SELECT pub_id,pub_name,pub_state,SUBSTR(pub_info,1,190) AS pub_info,pub_img FROM d_publishing where (pub_name LIKE '%$keyword%' or pub_info LIKE '%$keyword%') and and pub_state = '1' limit $row,20");
$results = array_merge($result1->result_array(), $result2->result_array());
return $results;
}
Now i want to modify the second query to something like that :
select all publishers from "publishers table" where the name of publisher is like $keyword and this $keyword doesn't exist in authors table ..
I mean if this name exist in authors don't select it in publishers
How can i translate that meaning to Mysql Query
First, check out sql-injections before continuing to develop in your ebook-application. Looks like your keyword is not checked to be a safe parameter. And just to be sure, do you know about csrf and xss? If not, check about that too. This is very important.
Secondaly, you should consider working on your database design to avoid having duplicated values. Check out "database normalization" for more information. Seems like you could do another table to extract your "contact information" like name, state, id etc. This would make it possible for your author-table and publisher-table to use a "contact_id" referencing the contact-information-table.
Last but not least, to answer your question, you can generelly solve such problems with an "anti join". Use a left join on the authors table in the second query and check for "IS NULL" on matches with the publisher table. More information here: http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null-mysql/
I do not know if I understand your database design completly right, but it also seems like an UNION combined with a DISTINCT could help you - and you wouldn't even need this array_merge-stuff. I would suggest you to check out these two commands in the mysql docs.
I have a bunch of tables that are like Client# and the # changes. Is there a way to create a query to query that table based on the client number you get from logging in as their use?
Example to give idea:
$q2 = "SELECT * FROM users WHERE username = '".$_SESSION['username']."'";
$result2 = mysql_query($q2,$conn);
$row = mysql_fetch_assoc($result2);
$_CLIENT_ID = $row['CLIENTID'];
$q2 = "SELECT * FROM client+".$_CLIENT_ID."";
Is there a better way to do this?
I'm trying to keep clients in their own tables so they do not get to massive.
I'm trying to keep clients in their own tables so they do not get to massive.
This is almost always the wrong strategy. The table size isn't as important as how you have indexed it for access, and it can be partitioned later, should that become necessary. The proper way to handle this is simply a column in one table which identifies the client id.
With a proper client-identifying column you can query as:
SELECT othertable.*
FROM
users
JOIN othertable ON users.CLIENTID = othertable.CLIENTID
WHERE users.username = '$_SESSION['username']'
Dealing with dynamic table names becomes troublesome not only because it is more difficult to query against. You cannot, for example, use a placeholder in place of a table name with many parameterized query APIs like PDO & MySQLi:
// Won't work with a PDO prepared statement. :clienttable place holder isn't allowed
SELECT * FROM :clienttable WHERE value=:someval
sorry for the extremely basic question!! I'm very new to PHP/MySQL
How would it be possible to do an if statement referencing wherever or not data was from a certain table.
Would this work?
if ( $search FROM "table2" )
{
function for table2.. etc
}
TABLE:INSTRUMENTS
COLUMNS:
id instrument grade standard comments
instrument2 grade2 standard2 comments2
instrument3 grade3 standard3 comments3
instrument4 grade4 standard4 comments4
instrument5 grade5 standard5 comments5
TABLE: PEOPLE
COLUMNS:
id first last snumber course email graduate inumber
Basically a person from the PEOPLE table is linked via ID to instruments in the INSTRUMENTS table, I have an e-mail search function that I need to send out the relative data to the relative instruments.
I want to get the comments[i] , grade[i], standard[i] of the matching instrument[i]
Somewhere in your code you must already have specified the table to select from. You can use the same logic to see which table you initially used?
For example:
$sTable = 'table2';
$rResult = mysql_query(sprintf($sQuery, $sTable));
if ($sTable == 'table2') { // use $rResult }
You know what table it came from, because you retrieved it from that table.
Update
Perhaps:
$search = trim(stripslashes($_POST['search']));
$search = mysql_real_escape_string($search);
//Find instruments searched for:
$query = "
SELECT *,
('$search' IN `instrument`) AS `matched1`,
('$search' IN `instrument2`) AS `matched2`,
('$search' IN `instrument3`) AS `matched3`,
('$search' IN `instrument4`) AS `matched4`,
('$search' IN `instrument5`) AS `matched5`
FROM `instruments`
WHERE '$search' IN (`instrument`, `instrument2`, `instrument3`, `instrument4`, `instrument5`)
";
Explore the results and find out how to use them to your advantage.
This isn't the most glamourous solution and you can no doubt improve this with a different approach, but it's something to get you started.
Hmm,
The tables need a redesign IMHO.
I would change table instruments to.
id, people_id, instrument, grade, standard, comments
This query:
SELECT
people.email
,instruments.instrument
,instruments.grade
,instruments.standard
,instruments.comment
FROM people
INNER JOIN instruments ON (instruments.people_id = people.id)
WHERE people.id = 10
Will give you all instruments for person number 10.
You can change the where clause to where people.snumber = x or whatever you feel like.
Or add extra clauses to limit the number of instruments by adding something like : AND instrument.grade > 7 at the end
With this setup people can have any number of instruments.
It feels a bit odd to -reverse link- the instruments to people like this, but believe me... it works.
I recommend reading up on joins (google 'mysql join') and always use explicit joins using the join keyword, it makes understanding your queries much easier.
If this is the result you where looking for, then you can drop the inumber field from the people table, since we moved the link between people and instruments to the instrument table.
On an 1-to-many link the linking field should always be on the 'many'-table.
You would need to store what table the search result was from in a variable, and compare the two variables.
if($search === "table2")
There is no from operator in PHP.