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);
Related
I am starting to get headaches over this so I thought I just post it here.
I have two tables that are related through a pivot table (as it is a many-to-many relationship). I use Laravel and Eloquent (but general help on how to achieve this with normal SQL queries is also highly appreciated).
I want to order the first table based a column of the second one but the column needs to be "aggregated" for this.
Example with Cars that are shared by many drivers and can have different colors:
Car-Table: [id, color]
Driver-Table: [id, name]
Car.Driver-Table: [car_id, driver_id]
I need a query that gets all drivers that only drive red cars and then all that don't drive red cars.
I have to use a query because I'll maybe do other things (like filtering) on this query afterwards and want to paginate in the end.
I already use queries that get either one of the two groups. They look like this:
In the Driver model:
public function redCars() {
return $this->cars()->where('color', 'red');
}
public function otherColoredCars() {
return $this->cars()->where('color', '<>', 'red');
}
And then in somewhere in a controller:
$driversWithOnlyRedCars = Driver::whereDoesntHave('otherColoredCars')->get();
$driversWithoutRedCars = Driver::whereDoesntHave('redCars')->get();
Is there a way to combine these two?
Maybe I am just thinking completely wrong here.
Update for clarification:
Basically I would need something like this (ot any other way that would lead to the same outcome)
$driversWithOnlyRedCars->addTemporaryColumn('order_column', 0); // Create temporary column with value 0
$driversWithoutRedCars->addTemporaryColumn('order_column', 1);
$combinedQuery = $driversWithOnlyRedCars->combineWith($driversWithoutRedCars); // Somehow combine both queries
$orderedQuery = $combinedQuery->orderBy('order_colum');
$results = $combinedQuery->get();
Update 2
I think, I found out how to get near my goal with raw queries.
Would be something like this:
$a = DB::table(DB::raw("(
SELECT id, 0 as ordering
FROM drivers
WHERE EXISTS (
SELECT * FROM cars
LEFT JOIN driver_car ON car.id = driver_car.car_id
WHERE driver.id = driver_car.driver_id
AND cars.color = 'red'
)
) as only_red_cars"));
$b = DB::table(DB::raw("(
SELECT id, 1 as ordering
FROM drivers
WHERE EXISTS (
SELECT * FROM cars
LEFT JOIN driver_car ON car.id = driver_car.car_id
WHERE driver.id = driver_car.driver_id
AND cars.color <> 'red'
)
) as no_red_cars"));
$orderedQuery = $a->union($b)->orderBy('ordering');
Now the problem is that I need the models ordered like this and paginated in the end so this is not really an answer to my question. I tried to convert this back to models but I didn't succeed yet. What I tried:
$queriedIds = array_column($orderedQuery->get()->toArray(), 'id');
$orderedModels = Driver::orderByRaw('(FIND_IN_SET(drivers.id, "' . implode(',', $queriedIds) . '"))');
But looks like FIND_IN_SET only allows for a column of the table as second parameter. Is there another way to get the Models in the right order out of the ordered union query?
You can use a UNION query:
$driversWithOnlyRedCars = Driver::select('*', DB::raw('0 as ordering'))
->whereDoesntHave('otherColoredCars');
$driversWithoutRedCars = Driver::select('*', DB::raw('1 as ordering'))
->whereDoesntHave('redCars');
$drivers = $driversWithOnlyRedCars->union($driversWithoutRedCars)
->orderBy('ordering')
->orderBy('') // TODO
->paginate();
How do you want drivers with the same ordering to be ordered? You should add a second ORDER BY clause to get a consistent order every time you execute the query.
This is the best I got:
$driversWithOnlyRedCars = Driver::whereHas('cars',function($q){
$q->where('color', 'red');
})->withCount('cars')->get()->where('cars_count',1);
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'm developing in php/sql a web application where users will be able to post items that they'd like to sell ( kinda like ebay ). I want non-members to be able to comment on the items or ask queries about items.
My problem is I want to display each item as well as any comment/query made about that item, in a similar manner as the way Facebook wall works.
I want to "append comments"(if any) to each item. The comments table is linked to the items table via column item_id. And the items table is linked to users table via column user_id. I have left joined users table with items table to display item details, i tried to left join comments table as well so that there are 3 joined tables.
That fails because no comments are displayed and only one item is displayed, despite there being multiple entries in each table. Here is the code i,m using.
$database->query
('
SELECT sale.*, query.*, users.id AS userid, users.username as user
FROM sale
LEFT JOIN users ON sale.user_id = users.id
LEFT JOIN query on sale.id = query.item_id
where category = "$category" ORDER BY sale.id DESC
');
$show = " "; //variable to hold items and comments
if ($database->count() == 0) {
// Show this message if there are no items
$show .= "<li class='noitems'>There are currently no items to display.</li>" ;
} else {
$show .= "<li>";
while ( $items = $database->statement->fetch(PDO::FETCH_ASSOC) )
{
$show .= "
//show item details in html
";
while( $query = $database->statement->fetch(PDO::FETCH_ASSOC) )
{
$show .= "
//show queries below item details
";
}
$show .= "</li>" ;
}
Welcome to Stackoverflow!
I recommend you taking a look at pdo. If you are already using mysql_ functions, then I recommend you switch. More on that can be found here.
Now that your pointed to the direction of to what functions to use when connecting/running queries, you now should create your tables. I use phpmyadmin for managing my database, I find it very good, but it's up to you what you use. Once you've decided on the service you use to manage your database, you should then learn how to use it by doing some google searches.
Now you need to set up your table and structure it correctly. If you say you're having items, then you should make a table called items. Next create the columns to the properties of the items. Also I recommend reading about Database Normalization, which is a key aspect of setting up your SQL tables Etc.
Once you have everything set up, you've connected to your database successfully Etc. You now need to set up the "Dynamic Page". What I mean by this is, there's only one page, say called 'dynamic', then a variable is passed to the url. These are called GET HTTP requests. Here's an example of what one would look like: http://example.com/item?id=345.
If you've noticed, you'll see the ? then the id variable defined to 345. You can GRAB this variable from the url by accessing the built in PHP array called $_GET[]. You can then type in your variable name you want to fetch into the []'s. Here's an example.
<?php
$data = $_GET['varname']; // get varname from the url
if(isnumeric($data)){ // is it totally made out of numbers?
$query = "SELECT fieldname FROM table WHERE id=:paramname";
$statement = $pdo->prepare($query); // prepare's the query
$statement->execute(array(
'paramname'=>$data // binds the parameter 'paramname' to the $data variable.
));
$result = $statement->fetch(PDO::FETCH_ASSOC); // grabs the result of the query
$result = $result['fieldname'];
echo 'varname was found in the database with the id equal to:'.$data.', and the result being: '.$result;
}
?>
So now you can see how you can grab the variable from the url and dynamically change the content with-in the page from that!
Hope this helped :)
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
I have two primary MySQL tables (profiles and contacts) with many supplementary tables (prefixed by prm_). They are accessed and manipulated via PHP.
In this instance I am querying the profiles table where I will retrieve an Owner ID and a Breeder ID. This will then be referenced against the contacts table where the information on the Owners and Breeders is kept.
I received great help here on another question regarding joins and aliases, where I was also furnished with the following query. Unfortunately, I am having huge difficulty in actually echoing out the results. Every single site that deals with Self Joins and Aliases provide lovely examples of the queries - but then skip to "and this Outputs etc etc etc". How does it output????
SELECT *
FROM (
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts ownerContact
ON profiles.ProfileOwnerID = ownerContact.ContactID
LEFT JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON profiles.ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
) ilv LEFT JOIN contacts breederContact
ON ilv.ProfileBreederID = breederContact.ContactID
WHERE ProfileName != 'Unknown'
ORDER BY ilv.ProfileGenderID, ilv.ProfileName ASC $limit
Coupled with this is the following PHP:
$owner = ($row['ownerContact.ContactFirstName'] . ' ' . $row['ownerContact.ContactLastName']);
$breeder = ($row['breederContact.ContactFirstName'] . ' ' . $row['breederContact.ContactLastName']);
All details EXCEPT the contacts (gender, colour, etc.) return fine. The $owner and $breeder variables are empty.
Any help in settling this for me would be massively appreciated.
EDIT: My final WORKING query:
SELECT ProfileOwnerID, ProfileBreederID,
ProfileGenderID, ProfileAdultColourID, ProfileColourModifierID, ProfileYearOfBirth,
ProfileYearOfDeath, ProfileLocalRegNumber, ProfileName,
owner.ContactFirstName AS owner_fname, owner.ContactLastName AS owner_lname,
breeder.ContactFirstName AS breeder_fname, breeder.ContactLastName AS breeder_lname,
BreedGender, BreedColour, BreedColourModifier
FROM profiles
LEFT JOIN contacts AS owner
ON ProfileOwnerID = owner.ContactID
LEFT JOIN contacts AS breeder
ON ProfileBreederID = breeder.ContactID
LEFT JOIN prm_breedgender
ON ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN prm_breedcolour
ON ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
WHERE ProfileName != 'Unknown'
ORDER BY ProfileGenderID, ProfileName ASC $limit
Which I could then output by:
$owner = ($row['owner_lname'] . ' - ' . $row['owner_fname']);
Many Thanks to All!
I guess you're using the mysql_fetch_array or the mysql_fetch_assoc-functions to get the array from the result-set?
In this case, you can't use
$row['ownerContact.ContactFirstName']
as the PHP-Docs read:
If two or more columns of the result have the same field names, the
last column will take precedence. To access the other column(s) of the
same name, you must use the numeric index of the column or make an
alias for the column. For aliased columns, you cannot access the
contents with the original column name.
So, you can either use an AS in your SQL-query to set other names for the doubled rows or use the numbered indexes to access them.
This could then look like this:
Using AS in your Query
In your standard SQL-query, the columns in the result-set are named like the columns which their values come from. Sometimes, this can be a problem due to a naming-conflict. Using the AS-command in your query, you can rename a column in the result-set:
SELECT something AS "something_else"
FROM your_table
This will rename the something-column to something_else (you can leave the ""-quotes out, but I think it makes it more readable).
Using the column-indexes for the array
The other way to go is using the column-index instead of their names. Look at this query:
SELECT first_name, last_name
FROM some_table
The result-set will contain two columns, 0 ==> first_name and 1 ==> last_name. You can use this numbers to access the column in your result-set:
$row[0] // would be the "first_name"-column
$row[1] // would be the "last_name"-column
To be able to use the column-index, you'll need to use mysql_fetch_row or the mysql_fetch_assoc-function, which offers an associative array, a numeric array, or both ("both" is standard).
you need to replace the * with the data you need , and the similar ones you have to make aliases too :
ownerContact.ContactFirstName as owner_ContactFirstName
and
breederContact.ContactFirstName as breeder_ContactFirstName .
like this :
select ownerContact.ContactFirstName as owner_ContactFirstName , breederContact.ContactFirstName as breeder_ContactFirstName from profiles join ownerContact ... etc
in this way you will write :
$owner = ($row['owner_ContactFirstName'] . ' ' . $row['owner_ContactLastName']);
$breeder = ($row['breeder_ContactFirstName'] . ' ' . $row['breeder_ContactLastName']);
You cannot specify table alias when you access row using php. Accessing it by $row['ContactFirstName'] would work if you didn't have 2 fields with the same name. In this case whatever ContactFirstName appears second overwrites the first.
Change your query to use fields aliases, so you can do $owner = $row['Owner_ContactFirstName'].
Another option I'm not 100% sure is to access field by index, not by name(e.g. $owner=$row[11]). Even if it works I don't recommend to do so, you will have a lot of troubles if change your query a bit.
On outer select You have only two tables:
(inner select) as ilv
contacts as breederContact
there is no ownerContact at all