I am working on project which is in symfony 1.0
I have problem in creating propel query.
I have two table
car
id name
1 a
2 b
3 c
feature
id car_id feature
1 2 f1
2 2 f2
3 2 f3
4 1 f1
5 3 f3
6 3 f2
7 3 f4
Here is a SQLFiddle with table and value.
I have feature array(f1,f2,f3). Now I want only cars which has all three features i.e which is "b" in our case.
I have tried but not gives satisfied result
$c = new Criteria();
$c->clearSelectColumn();
$c->addSelectColumn(CarPeer::NAME);
$c->addSelectColumn(FeaturePeer::CAR_ID);
$c->addJoin(CarPeer::ID,FeaturePeer::CAR_ID,Criteria::LEFT_JOIN);
$c->add(FeaturePeer::FEATURE,array(f1,f2,f3),Criteria::IN);
$c->addGroupBy(CarPeer::ID);
$resultset = CarPeer::doSelectRs($c);
I believe this is the SQl you want (seems to work in my SQL Fiddle anyway):
SELECT car_id FROM
(SELECT COUNT(car_id) AS feature_count, car_id FROM feature
WHERE feature IN ('f1', 'f2', 'f3') GROUP BY car_id
) car_features
WHERE car_features.feature_count=3
Now to get that in Propel you need to do something like:
$features = array("f1", "f2", "f3");
$featureCount = FeatureQuery::create()
->withColumn("COUNT(car_id)", "feature_count")
->add(FeaturePeer::FEATURE, $features, Criteria::IN)
->addGroupBy(CarPeer::ID);
$cars = CarQuery::create()
->addSelectQuery($featureCount, "car_features")
->where("car_features.feature_count = ?", sizeof($features))
->find();
Related
this is sample product properties table
product_id property_id property_value
5 1 white
5 2 50
5 3 50
5 4 55
5 5 mm
6 8 cm
i want filter my products dynamically. for example:
select property_id 1 and property_value white
AND
select property_id 2 and property_value 50
AND
select property_id 4 and property_value 55
AND
etc ...
i can make dynamic query from a basic query. when i use all conditions together, no record matched because all conditions operator is AND. what is the best query?
thanks for your answers.
It sounds like you're using the wrong keyword. Use OR instead of AND between the sets of criteria:
SELECT DISTINCT product_id
FROM product_properties
WHERE
(property_id = 1 and property_value = 'white')
OR
(property_id = 2 and property_value = '50')
OR
(property_id = 4 and property_value = '55')
OR
etc ...
You can use DISTINCT if you just want one of each product_id that matches the various criteria, or leave it off to get one for each row that matches.
Heading ##The basic query is:
SELECT
a.`*`,b.`*`
FROM
properties AS a
JOIN
properties AS b
ON
a.`product_id` = b.`product_id`
WHERE
a.`property_id` = '1' AND a.`property_value` = 'white'
AND
b.`property_id` = '2' AND b.`property_value` = '50'
Thanks to #mikhail-vladimirov https://stackoverflow.com/a/15208055/5129662
This is what I want:
Users will send one or two values in my website and I will store them in two variables $genres1 and $genres2.
Like: If user sends, Action, then my code will show all movies with Action genres. If user sends Action+Crime, then my table will fetch all movies with Action+Crime.
Got it?
My current table structure is one to many relationship, like this
tmdb_id movie_title
-----------------------------
1 Iron man
2 Logan
3 Batman
4 The hangover
tmdb_id genres
-----------------------------
1 Action
1 Crime
2 Drama
2 Action
3 Crime
3 Action
4 Comedy
4 Drama
But the problem here is, I can't achieve what I explained above with this.
2nd option: I make a single table like this:
movie_tile genres1 genres2 genres3 genres4
----------------------------------------------------
Logan Action Crime Drama Null
Iron man Action Crime Null Null
And I can do what, I want with this single line:
SELECT * FROM movies WHERE (genres1='$genres1' or genres2='$genres1' orgenres1='$genres3' or genres3='$genres1')
Any other option?
use a table width genres
and use an other table connecting the movie to any genre
-----
movieid title
-----
1 Logan
2 Smurf
-----
-----
genreid genre
-----
1 animated
2 blue people
-----
-----
movieid genreid
-----
1 1
2 1
2 2
-----
that way you won't be limited to 4 genres per movie
now I read your question better.
That's what you do, but you put left out the genre-table.
The 2nd option is bad, as you limit yourself to only 4 categories
Is this connected to PHP? I think is easiest to solve this further by a join query, sorted by movie and a loop in PHP
you want all movies where (by user request) the genres are both Crime And Action?
SELECT mg.movieid, count(1), m.title
FROM movies_genres mg
JOIN movies m ON m.movieid mg.movieid
WHERE mg.genreid = 1 OR mg.genreid =3
group by mg.movieid, m.title
HAVING COUNT(1) = 2
edit: see other genres as well
SELECT movies.movieid,movies.title, genres.genre
FROM movies
JOIN movie_genre mg ON mg.movieid = movies.movieid
JOIN genres on genres.genreid = mg.genreid
WHERE movie.movieid IN (
SELECT mg.movieid
FROM movies_genres mg
WHERE mg.genreid = 1 OR mg.genreid =3
GROUP BY mg.movieid
HAVING COUNT(1) = 2
)
forgot to mention: count = 2, means you gave 2 genreid's to find. This could also be 1, 3 or 25
select distinct a.tmdb_id, a.movie_tittle
from movie_tittle a inner join genre_tittle b
on a.tmdb_id = b.tmdb_id
where b.genres in ('Action', 'Crime')
Based on your comment, try this :
SELECT
a.tmdb_id, a.movie_tittle
FROM
movie_tittle a inner join genre_tittle b
ON
a.tmdb_id = b.tmdb_id
WHERE
b.genres in ('Action', 'Crime')
GROUP BY
a.tmdb_id, a.movie_tittle
HAVING
count(a.tmdb_id) = 2
tmdb_id and genres in table genre_tittle should not duplicated. Make it as primary key.
But the problem here is, I can't achieve what I explained above with [the first two tables]
Yes, you can. Assuming the two tables are called movies and movie_genres, you can select the movies which have both tags using:
SELECT movie_title FROM movies
JOIN movie_genres genre1 USING (tmdb_id)
JOIN movie_genres genre2 USING (tmdb_id)
WHERE genre1.genres = 'Action'
AND genre2.genres = 'Crime'
See it for yourself here.
try something like this :
tableA
Movie_ID Movie_title
1 Iron man
2 Logan
3 Batman
4 The hangover
tableB
Genre_ID Genre_title
1 Action
2 Crime
3 Drama
4 Comedy
tableC
ID Movie_ID Genre_ID
1 1 1
2 1 2
3 2 2
4 2 3
query :
Select A.Movie_title,B.Genre_title
from tableC C
inner join tableA A on A.Movie_ID = C.Movie_ID
inner join tableB B on B.Genre_ID = C.Genre_ID
where
C.Genre_ID in (IFNULL(val1,0),IFNULL(val2,0))
you should make a relational table to solve you issues like so
movie table
movie_id movie_name genre_id
1 alien 2
2 logan 1
3 ps i love you 4
4 click 3
then you will need a genre table
genre table
genre_id genre_type
1 action
2 sci fi
3 comedy
4 romance
then your select would link the to tables
function get_movies_by_genre($genre_id) {
global $MySQLiConnect;
$query = '
SELECT *
FROM movies m
INNER JOIN genre g ON (g.genre_id = m.genre_id)
WHERE g.genre_id = ?
';
$stmt = $DBConnect->stmt_init();
if ($stmt->prepare($query)) {
$stmt->bind_param("i", $genre_id);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
}
return $rows;
}
or
function get_movies_by_genre($genre_id) {
global $MySQLiConnect;
$query = '
SELECT *
FROM movies m
INNER JOIN genre g ON (g.genre_id = m.genre_id)
WHERE g.genre_name = ?
';
$stmt = $DBConnect->stmt_init();
if ($stmt->prepare($query)) {
$stmt->bind_param("i", $genre_id);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
}
return $rows;
}
This is the base function to get you all information from the movie table depending on which genre id you send to it.
as for multiple ids you can then run the function through a foreach loop for as many genre_ids as you need and then display them as you need.
I hope this helps.
I have a table :
Person Language
6 1
6 2
6 3
7 1
7 2
I would like to select the person who speaks the language 1 AND 2 AND 3 (person 6)
I coded this query, but I don't get the right result :
SELECT guides.id, guides.nom, guides.prenom, langues.langue
FROM guides
JOIN guides_has_langues ON guides_has_langues.guides_id = guides.id
JOIN langues ON guides_has_langues.langues_id = langues.id
WHERE guides_has_langues.langues_id = 1 AND guides_has_langues.langues_id = 2 AND guides_has_langues.langues_id = 3
I think that this query select field that are 1 AND 2 AND 3, is it right ?
It's not my goal.
Select all entries for languages 1, 2 and 3. Then group by guide and stay with those having all three languages (using the HAVING clause). To show the languages use the function your dbms offers to concatenate them (e.g. GROUP_CONCAT for MySQL).
SELECT guides.id, guides.nom, guides.prenom, GROUP_CONCAT(langues.langue)
FROM guides
JOIN guides_has_langues ON guides_has_langues.guides_id = guides.id
JOIN langues ON guides_has_langues.langues_id = langues.id
WHERE guides_has_langues.langues_id IN (1,2,3)
GROUP BY guides.id, guides.nom, guides.prenom
HAVING COUNT(DISTINCT guides_has_langues.langues_id) = 3;
(If you want one line per guide and language this will be a little more complicated, because you need the raw entires plus the aggregation information on how many languages the guide speaks.)
My ch_skills table looks like
uid | skill1 | skill2 | skill3 | skill4 | skill5
1 1 2 2 0 1
2 1 1 2 1 1
3 1 2 3 0 1
My first question: is this correct? I mean would it be better if I made it like this:
uid | skillid | skill_lvl
1 1 1
1 2 2
1 3 2
1 4 0
1 5 1
Everything worked fine until now with the example #1, but now I'm in a trouble with the sql queries. Currently, I'm using 5 different queries to get the level of each skill. I use the following code:
For skill1:
$query = $this->db->prepare("SELECT `skills`.`skill_ID` as `Skill1_id`,
`skill_name`.`skill_name` as `Skill1_name`, `skill_level` as `Skill1_level`,
`skill_price` as `Skill1_price`
FROM `skills`, `skill_name`, `ch_skills`
WHERE `skill_name`.`skill_ID` = `skills`.`skill_ID`
AND `skills`.`skill_ID`= 1
AND `skills`.`skill_level` = `ch_skills`.`skill1`
AND `ch_skills`.`uid` = :uid");
For skill2:
$query = $this->db->prepare("SELECT `skills`.`skill_ID` as `Skill1_id`,
`skill_name`.`skill_name` as `Skill1_name`, `skill_level` as `Skill1_level`,
`skill_price` as `Skill1_price`
FROM `skills`, `skill_name`, `ch_skills`
WHERE `skill_name`.`skill_ID` = `skills`.`skill_ID`
AND `skills`.`skill_ID`= 2
AND `skills`.`skill_level` = `ch_skills`.`skill2`
AND `ch_skills`.`uid` = :uid");
And so on... As you can see, there's only two differences: skill_id = 2, and skill2 as the coulmn's name. Is there any way for querying all the 5 skills in only 1 query? Or would you recommend me anyway to change the table structure?
Note: skills stands for the skill prices, and skill_name for the skill's names.
As the other commenters have suggested, your best choice is to change the table exactly as you proposed.
The biggest reason not to have a wide table like you show in your first example, is that adding a skill means changing the structure of the database, which could break existing queries.
Secondly, as you see when you're trying to query the results, having a single table doesn't even make it easier to work with.
The only possible benefit to a non-normalized table like your example is that it takes up slightly less disk space. But in todays world, disk space should never be your primary concern.
To answer your question about querying the original non-normalized example, however, there are two ways to do it:
Use a union statement which would combine 5 distinct queries together. This is pretty inefficient
Create a table with (in this case) 5 rows (or if you have a Skills table use that). Then join the ch_skills table to that, which should take each row and split it 5 times. See below: (note: I'm assuming for the purposes of this example that skills and skill_name are in a 1:1 relationship and only have 5 records each)
SELECT skills.skill_ID,
skill_name.skill_name,
skill_level as Skill_level,
skill_price as Skill_price
FROM skills
JOIN skill_name on skill_name.skill_ID = skills.skill_ID
JOIN ch_skills
WHERE ch_skills.uid = :uid
AND ((skills.skill_ID = 1 AND skills.skill_level = ch_skills.skill1)
OR (skills.skill_ID = 2 AND skills.skill_level = ch_skills.skill2)
OR (skills.skill_ID = 3 AND skills.skill_level = ch_skills.skill3)
OR (skills.skill_ID = 4 AND skills.skill_level = ch_skills.skill4)
OR (skills.skill_ID = 5 AND skills.skill_level = ch_skills.skill5))
Still very new to all of this so bear with me.
Have 3 tables
table 1: member
Mem_index, Mem_name
1 joe
2 Mark
Table 2: Course
Course_index, Course_Name
1 Math
2 Reading
Table 3 : data
Data index,Member,Course,Score
1 1 1 85
2 1 2 75
3 2 1 95
4 1 2 65
SO what I would like to do is create a table:
Do a query and gather all of the courses, find the max score for each course and attribute the member name to it.
Table result should look like:
Course, Max score,name
Math 95 Mark
Reading 75 Mark
I can do the query individually but unsure of how to loop it and then propogate the data into the table.
How about this query for SQL?
SELECT c.course_name, MAX( d.score ), m.mem_name
FROM members m
JOIN data d on m.mem_id = d.member
JOIN course c on c.course_id = d.course
GROUP BY d.course
ORDER BY d.score, m.mem_name, c.course_name
Not sure if the field names match up but you get the idea - tested this in sql with some dummy data.
Data
Index Member Course Score
1 1 1 60
1 1 1 85
Course
course_id course_name
1 Math
2 English
3 Science
Members
mem_id mem_name
1 Mark
2 James
You will get the following
Course Name Score Member
Math 85 Mark
Try this query :
SELECT c.course_Name , MAX(d.score),m.mem_name
FROM data d
JOIN course c ON d.course=c.course_index
JOIN members m ON m.mem_index = d.member
GROUP BY d.course
ORDER by MAX(d.score) DESC