I'm trying to write up an email notification system for a job recruitment site I made and am currently looking at grouping a certain amount of jobs together before sending an email to the candidate
I have a table which I've called candidate_to_job which contains the candidate_id, job_id and an "emailed" boolean
What I'm struggling with is updating that table when a new job is posted and emails are sent out. So far when a new job is posted I run the following:
SELECT c2j.candidate_id, c2j.job_id, j.title
FROM " . DB_PREFIX . "candidate_to_job c2j
LEFT JOIN " . DB_PREFIX . "job j
ON (j.job_id = c2j.job_id)
WHERE c2j.emailed = 0
Then through PHP I group them all together so I have an array looking something like this:
$candidates = array(
1 => array(1,2,3),
2 => array(1,3),
3 => array(4,5,6)
);
With the array key being the candidate ID and the value an array of job IDs
What I want to do using that array - after the emails have been sent - is update the candidate_to_job table setting emailed to true, e.g candidate_id 1 would have emailed set to true for job_ids 1, 2 and 3
Is there a way I can do this in one query? I've looked at WHEN CASE statements but I don't think that applies in this case? I really don't want to run multiple queries per candidate because there could potentially be thousands!
You can run one UPDATE query per group provided that the group can share the same WHERE criteria and the same update values.
UPDATE tbl SET value = TRUE WHERE id IN(1,2,3,4,5,6);
UPDATE tbl SET value = FALSE WHERE id IN(7,8,9,10,11);
Or you can use the WHEN clause or even some IF clauses provided that the criteria are simple enough.
UPDATE tbl SET value = IF(id = 1) WHERE id IN(1,2);
UPDATE tbl
SET value = CASE
WHEN id IN (1,2,3,4,5,6) THEN TRUE
WHEN id IN (7,8,9,10,11) THEN FALSE
ELSE value
END
WHERE id IN (1,2,3,4,5,6,7,8,9,10,11);
Having possibly thousands of WHEN cases, may be a hassle to build/change, I'd go with the first option:
Flip the old key=>value array and keep all ids connected to a value:
foreach($list AS $id => $value) {
$list2[$value][] = $id;
}
Iterate through the value=>keys array and build UPDATE queries that can bulk update the value for all keys at once.
If you are using mysqli extension in PHP instead of mysql, you can also write mutliple statements seperated by ';' and send all of them in one query. This might result in slightly simpler code than a complex UPDATE with cases.
I dont think this costs much more performance than one single complex UPDATE statement.
Is this what you're after? You can do a join using from and where without having to dynamically generate SQL in PHP.
UPDATE " . DB_PREFIX . "candidate_to_job c2j
SET emailed = 1
FROM " . DB_PREFIX . "job j
WHERE j.job_id = c2j.job_id and
c2j.emailed = 0
Related
Quite new to all the SQL/PHP stuff - dabbled with basic queries and outputting them to PHP previously but now trying something a bit more complicated and hoping someone can help with this as I've been trying to work it out with no luck so far:
I have 2 MS SQL tables:
Table 1 - Faults
faultid ... requestnumber
1 ........... 6
2 ........... 5
3 ........... 6
Table 2 - actions
faultid ....who ..... when...... timetaken
1.......... John....... Mon......... 1.00
2.......... Peter...... Mon.......... 2.00
3.......... Luke....... Tues........ 1.00
2.......... John....... Tues........ 0.5
1.......... Mike....... Mon......... 0.75
What I am trying to achieve is create a variable I can use in a front end php based webpage that gets a sum of the timetaken column in Table 2 where the requestnumber in Table 1 is equal to a specific number (i.e. 6)
I'm guessing it will start with something like:
$sql1 = "select faultid FROM Faults WHERE requestnumber = '6'";
$sqlresult = sqlsrv_query($conn, $sql1);
while ($row = sqlsrv_fetch_array($sqlresult)){
}
After that I get a bit stuck. How do I take each result from this and then run another query to get the sum of the timetaken column in Table 2 for just the corresponding faultid's? I want to hazard a guess at using foreach but not sure on the syntax (or even if I'm guessing correctly).
So in this example I would get back a result of 2.75 as a variable in PHP.
Any help would be appreciated. Thanks in advance.
Andy
Best to use just one SQL-statement
$sql = 'SELECT SUM(t2.timetaken)';
$sql .= ' FROM Faults t1 INNER JOIN actions t2 ON (t2.faultid = t1.faultid)';
$sql .= ' WHERE t1.requestnumber = ?';
Use this as prepared statement and pass your requestnumber (6 or something) as argument when executing this statement.
To get all or multiple sums you can use group by (maybe combine with WHERE):
SELECT t1.requestnumber, SUM(t2.timetaken)
FROM Faults t1
INNER JOIN actions t2 ON (t2.faultid = t1.faultid)
GROUP BY t1.requestnumber
Edit:
According to your own comment, you can use a SELECT with subquery, but use IN, not =. When using '=' the subquery must return only one row.
select SUM (timetaken) FROM actions WHERE faultid IN (select Faultid from Faults WHERE requestnumber = '6')
-- ^^
But this way is usually slower than the one I posted above
I'm working on a school project, and I need this to work. I'm currently checking if my logged in users role is higher than a value, if they're great.
Instead of using precise values I'm using higher than and lower than (<=>).
I don't feel like you have to see that code.
In my MySQL Select Query I have the following:
PHP Code (Inside my $mysqli->query() which is set to a variable):
SELECT * FROM coachteam, teams, userteam WHERE (fk_coachteam_team_id = team_id AND fk_coachteam_user_id = '".$sessionRow['user_id']."')
OR (fk_userteam_team_id = team_id AND fk_userteam_user_id = '".$sessionRow['user_id']."')
In my database I have tables called as you see above: coachteam, teams, userteam .
All of the fields are valid. How do I know? When I try to fetch my result I get nothing, but if I remove one of the OR conditions or I add my user to both of my many-to-many tables, results will be fetched. But not if I have my user in one of the many-to-many table.
So example:
If I only have my user in either coachteam or userteam, my result isn't able to fetch any arrays, if I have my user in both of these, it will be able to.
If I remove one of the OR conditions, and only have my user in one of the many-to-many, it will work with the condition specified in the MySQL.
Shouldn't it behave like, if one of the conditions is true, then use that and fetch information from that.
Help appreciated, gotta hand this in tomorrow
When I use multiple ORs or ANDs grouped together it's good to double group them.
It's also good in MySQL when comparing data from multiple tables to include the table in the operator that you're getting the field from.
$sql = "
SELECT
*
FROM
`coachteam`,
`teams`,
`userteam`
WHERE
(
( `table-name`.`fk_coachteam_team_id` = `table-name`.`team_id` )
AND
( `table-name`.`fk_coachteam_user_id` = '" . $sessionRow['user_id'] . "')
)
OR
(
( `table-name`.`fk_userteam_team_id` = `table-name`.`team_id`)
AND
( `table-name`.`fk_userteam_user_id` = '" . $sessionRow['user_id'] . "')
)
";
$a = mysqli_fetch_assoc( mysqli_query($connection, $sql) );
var_dump($a);
I have 3 tables, and i have joined them together, which works fine, it pulls the information. One of the tables as an array within a column, on every row like:
["Pets","Schools","Shops"]
I need, while selecting, the query to pull out when a MATCH AGAINST a var. Here is my code:
$searchRefine = '';
foreach( $refineAmen as $key => $val) {
$searchRefine = $searchRefine . " MATCH(pa.Property_Amenities) AGAINST ('".$val."' IN BOOLEAN MODE) OR ";
}
The above takes each var from the array from the row / column, and adds it to a sub-query string.
$searchRefine = substr($searchRefine, 0, -3);
The above takes out the last 3 (or the word 'OR') at the end as its not needed
$detail = "SELECT p.*, pi.*, pa.* FROM tbl_property p LEFT join tbl_property_images pi on p.Property_Id = pi.Property_Id LEFT join tbl_property_amenities pa on pi.Property_Id = pa.Property_Id WHERE (p.Property_Postcode='" . $_POST['cust_id'] . "' OR p.Property_City Like '%" . $_POST['cust_id'] . "%') AND ( " . $searchRefine. " ) GROUP BY pi.Property_Id";
The above takes the sub strings and adds it to the final for firing. I do not get any errors.
The issue is, it does not pull the records with any of these key works within the row, just One. I have tried a number of combinations of AND or OR, so the query understands. But still no luck. Any someone look at this, and see if they can see what I have done wrong.
Thanks
You should normalize your database structure instead of storing multiple values in one column. This way you would not have to compute a sub-query string for fulltext search with MATCH...AGAINST.
Can you show your database structure?
Beware of SQL injection. Once your query is working you should alter it to escape client data oder use prepared statements.
I have two tables:
task
id name dueDate completed projectID
project
id name dueDate completed
I need to query both tables for rows with the same data. I tried doing a sample statement just looking for rows with completed=0, but never got any results. I think it has to do with using OR instead of AND, but it's just a little above my level right now...Any ideas?
TO CLARIFY, I'm not looking for duplicate rows, I'm looking for 'all tasks and projects with completed = 0'
The query is:
SELECT * FROM "task" t, "project" p WHERE t.dueDate = "2012-08-17" OR p.dueDate = "2012-08-17" AND t.completed = 0 OR p.completed = 0
I did manage to get one of the answers' code to work, however I realized that my entire app was written to talk to one table, and that it would be much easier to just combine the task and project table and use an isProject column to differentiate projects from tasks. This also adds the ability to nest projects inside of projects, because projects will now have a projectID column as well.
In the end, KISS prevails...
Thanks for all the help! I will mark the answer that worked, even though I won't be using it.
Try using parenthesis.
SELECT * FROM "task" t, "project" p WHERE (t.dueDate = "2012-08-17" OR p.dueDate = "2012-08-17") AND (t.completed = 0 OR p.completed = 0)
If You want only values matches from both tables with completed=0 from dueDate='2012-08-17':
You can use join to bound that tables results into one.
Inner join will return only results which matches on both sides.
So You can use it to match them in both tables by it and then filter for Your wanted value by classic where:
select * from task t inner join project p on t.dueDate = p.dueDate and t.completed = p.completed
where t.dueDate = '2012-08-17' and t.completed = 0
Try this instead:
SELECT dueDate, completed
FROM task AS t
WHERE (dueDate = "2012-08-17" AND completed = 0)
UNION ALL
SELECT dueDate, completed
FROM project AS p
WHERE (dueDate = "2012-08-17" AND completed = 0)
This should give you all records from each table where dueDate = "2012-08-17" and completed = 0.
I have two table named test and result.
If candidates register then it will be inserted in test table.
If candidate completed test then details has been inserted into result table.
Now I need a query to compare two table and populate detail candidates those who are not complete the test by using candidate id. I am using zend frame work please guide me
I am using this code but it does not work
$dbTableInfo = $this->getDbTable()->info();
$select->from(array(
'c1' => 'test'),
array('c1.candidate_id',
"CONCAT( c1.first_name,
' ',
c1.last_name ) AS full_name",
'c1.active',
'c1.sendlink',
'c1.date_added',
'c1.username',
'c1.date_modified',
'c1.test_id')
);
$select->joinLeft(array('re'=>'result'));
$select->where("c1.business_id='" . $cid . "' AND 'c1.candidate_id NOT IN(re.candidate_id)'");
$select->order('c1.candidate_id');
Sorry for not answering your question, but why don't you simply use a single table with a discriminator field, which would be called type for example, and use it this way:
If a candidate registers he will be inserted with type set to test
If a candidate completed the tests then his type would be changed to completed
Maybe you forgot to specify condition In joinLeft?
from zend docs :
LEFT JOIN with the joinLeft(table, condition, [columns]) method. All
rows from the left operand table are included, matching rows from the
right operand table included, and the columns from the right operand
table are filled with NULL if no row exists matching the left table.
and in your query you didnt specify neither the condition nor the columns you want returned.
for example you can do your join like this :
$select->from(array(
'c1' => 'test'),
array('c1.candidate_id',
"CONCAT( c1.first_name,
' ',
c1.last_name ) AS full_name",
'c1.active',
'c1.sendlink',
'c1.date_added',
'c1.username',
'c1.date_modified',
'c1.test_id')
);
$select->joinLeft(
array('re'=>'result'),
'"c1".candidate_id = "re".candidate_id',
"*"
);