Table Products
ad_id| property_id | property_value_id
69 4 1
69 7 6
69 6 3
67 7 6
...
For Example:
I need to search ((where property_id = 4 and property_value_id = 1) and (where property_id = 7 and property_value_id = 6))
Result should be: 69
The values im searching for are dynamic.
SELECT DISTINCT ad_id
FROM
(SELECT ad_id
FROM Producst
WHERE (property_id = 4 AND property_value_id = 1)
OR (property_id = 7 AND property_value_id = 6)
OR (property_id = 6 AND property_value_id = 3)
group by ad_id
having count(ad_id) = 3) as subquery
Should do the job.
You can join the table with itself three times, one for each pair of searched value. The query can take the form:
select distinct a.ad_id
from my_table a
join my_table b on b.ad_id = a.ad_id
join my_table c on c.ad_id = a.ad_id
where a.property_id = 4 and a.property_value_id = 1
or b.property_id = 7 and b.property_value_id = 6
or c.property_id = 6 and c.property_value_id = 3
Related
I need help, just stucked here.
I have matches table.
id product_id property_id
1 1 1
2 1 2
3 1 3
4 1 4
5 2 1
6 2 2
7 2 3
8 3 1
9 3 2
10 3 3
11 3 4
12 3 5
What I need to have in result of sql query is:
product_id 1 2 3 4 5
1 1 2 3 4 null
2 1 2 3 null null
3 1 2 3 4 5
Thanks a lot in advance.
Additional. So far I tried another way, but it's too complicated. I cross joined filtered properties to obtain a result.
SELECT t1.id, t1.product_id, t1.property_id as pr_id1, t2.property_id as pr_id2
FROM
(SELECT * FROM matches WHERE (property_id = 25 OR property_id = 39)) t1
CROSS JOIN
(SELECT * FROM matches WHERE (property_id = 29)) t2
ON t1.product_id = t2.product_id
select
product_id,
case when sum(case when property_id = 1 then 1 else 0 end )>0 then 1 end '1',
case when sum(case when property_id = 2 then 1 else 0 end )>0 then 2 end '2',
case when sum(case when property_id = 3 then 1 else 0 end )>0 then 3 end '3',
case when sum(case when property_id = 4 then 1 else 0 end )>0 then 4 end '4',
case when sum(case when property_id = 5 then 1 else 0 end )>0 then 5 end '5'
from
t
group by product_id
http://sqlfiddle.com/#!9/ce02aa/3/0
Thank you all for help, it gave me couple hints.
I found alternative way to do this with crossjoins.
Basically I crossjoin as much tables as I have attributes / properties pairs.
SELECT t1.id,
t1.subproduct_id,
t1.property_id as pr_id1,
t2.property_id as pr_id2,
t3.property_id as pr_id3,
FROM
(SELECT * FROM subproduct_attributes WHERE (property_id = 25 OR property_id = 30)) t1
CROSS JOIN
(SELECT * FROM subproduct_attributes WHERE (property_id = 28)) t2
ON t1.subproduct_id = t2.subproduct_id
CROSS JOIN
(SELECT * FROM subproduct_attributes WHERE (property_id = 27)) t3
ON t1.subproduct_id = t3.subproduct_id
Here is the code of laravel implementation.
$query = $this->builder->Join('subproduct_attributes AS first', 'first.subproduct_id', '=', 'subproducts.id')
->select('subproducts.*',
DB::raw('first.subproduct_id AS sub_id'),
DB::raw('first.property_id AS prop_id'));
$previous_table = 'first';
$i = 1;
foreach ($array as $slug => $attribute) {
$keys = [];
foreach ($attribute as $property_key => $value) {
// Quick check for property existence
if (AttributeProperty::find($property_key)) {
$keys[] = $property_key;
}
}
// if it is first iteration do not crossjoin
if ($i == 1) {
$query->whereIn('first.property_id', $keys);
} else {
$query->crossJoin("subproduct_attributes AS $slug", function ($join) use ($keys, $slug, $previous_table) {
$join->on("$slug.subproduct_id", '=', "$previous_table.subproduct_id")
->whereIn("$slug.property_id", $keys);
});;
$previous_table = $slug;
}
$i++;
}
I have 2 tables in mysql database.
a) company
cid company_name
===================
1 AstraZeneca
2 Emirates
3 Development Bank of Singapore
4 Royal Copenhagen
5 xxx
6 xxx
2) history
hid user_id view_id is_save mark_as view date
==============================================================
1 2 2 0 3 2016-08-25 22:06:12
2 3 3 1 3 2016-08-25 22:07:12
3 3 3 0 1 2016-08-25 22:08:12
4 3 2 0 1 2016-08-25 22:09:12
5 2 4 0 1 2016-08-25 22:10:12
6 4 5 0 1 2016-08-25 22:11:12
7 4 6 0 1 2016-08-25 22:12:12
This view_id is containing cid value.
Now, always I want to show latest 5 company_name from company table as ascending order based on history table view_id.
For that purpose I am doing following query. But company_name is not showing either ASC or DESC order
Here is the query :
$getViewID3 = mysqli_query($link, "SELECT view_id, hid, is_save FROM history WHERE user_id = '$user_id' AND mark_as = 3 GROUP BY view_id ORDER BY view_date DESC LIMIT 5 ");
if(mysqli_num_rows($getViewID3) > 0 ) {
while( $fetchViewId3 = mysqli_fetch_array($getViewID3) ) {
$viewid3 = (int) $fetchViewId3['view_id'];
$hid3 = (int) $fetchViewId3['hid'];
$is_save3 = (int) $fetchViewId3['is_save'];
$getCompany = mysqli_query($link, "SELECT company_name FROM company WHERE cid = '$viewid3' ORDER BY company_name DESC");
if(mysqli_num_rows($getCompany) > 0 ) {
while ($fetchCompany2 = mysqli_fetch_array($getCompany)) {
$cName = htmlspecialchars($fetchCompany2['company_name']);
$url_link = "{$url}company.php?cid=$viewid";
if($is_save3 == 1) {
$checked = 'checked = "checked"';
} else {
$checked = '';
}
echo "<li><a onClick='window.document.location=\"$url_link\"'> $cName </a> <input type='checkbox' class='data_save' $checked data-hid='$hid' data-saveid='$viewid3' name='save_history'></li>";
}
}
}
For example : Result is showing : A, E, D, R, L letter order.
It's should be show : A, D, E, L, R letter Order from company_name column.
If I didn't misunderstand:
SELECT
C.company_name
FROM company C
INNER JOIN
(
SELECT
view_id,
MAX(view_date) max_view_date
FROM history
WHERE is_save IN (0,1) AND mark_as = 3
GROUP BY view_id
ORDER BY max_view_date DESC
LIMIT 5
) AS t
ON C.cid = t.view_id
ORDER BY C.company_name ASC;
Note:
Since you want latest 5 companies the following query will put the last view_date beside the view_id.
Now if you sort these rows based on descending order of max_view_date and later limit the result to 5 then you will get at most five view_ids from the inner query.
Later a simple INNER JOIN between this result set and your company table will finish the job.
Sorry, sorting the final result in ascending order of company name will finish the job.
EDIT:
In order to get all the columns from history table and company_name column from company table:
SELECT
C.company_name,
t.*
FROM company C
INNER JOIN
(
SELECT
history.*
FROM history
INNER JOIN
(
SELECT
view_id,
MAX(view_date) max_view_date
FROM history
WHERE is_save IN (0,1) AND mark_as = 3
GROUP BY view_id
ORDER BY max_view_date DESC
LIMIT 5
) AS latestHistory
ON history.view_id = latestHistory.view_id AND history.view_date = latestHistory.max_view_date
) AS t
ON C.cid = t.view_id
ORDER BY C.company_name ASC;
This is the current query:
SELECT schedule.routenr, stops.stopname, schedule.scheduletime FROM schedule
INNER JOIN stops ON
schedule.id_stop=stops.id_stop
INNER JOIN tram ON
schedule.id_tram=tram.id_tram
WHERE tram.id_direction = '5' AND stops.stopname = 'Stourton' AND
schedule.scheduletime >= ('10:50:00')
OR tram.id_direction = '5' AND stops.stopname = 'CitySquare'
ORDER BY schedule.routenr ASC, schedule.scheduletime ASC;
These are the results displayed:
route_nr stopname scheduletime
1 CitySquare 09:57:00
2 Stourton 11:50:00
2 CitySquare 11:57:00
3 Stourton 12:50:00
3 CitySquare 12:57:00
Query Results with adding HAVING COUNT(schedule.routenr) > 1
route_nr stopname scheduletime
2 Stourton 11:50:00
I want to be able to display both records that have the duplicate count in route_nr so that stopname = Stourton and stopname = CitySquare are both displayed. This is what it should display.
route_nr stopname scheduletime
2 Stourton 11:50:00
2 CitySquare 11:57:00
3 Stourton 12:50:00
3 CitySquare 12:57:00
This is the list of Tables with data:
tram stops
id_tram id_direction id_stop stopname
1 1 1 GrimesDyke
2 1 2 SeacroftRingRoad
3 1 3 WykeBeck
4 1 4 FfordeGrene
5 2 5 St.James'sHospital
6 2 6 QuarryHill
7 2 7 Eastgate
8 2 8 CitySquare
9 2 9 Bodington
10 2 10 HeadingleyCentre
11 3 11 HydeParkCorner
12 3 12 UniversityofLeeds
13 3 13 Civic
14 4 14 Riverside
15 5 15 ClarenceDock
16 StJoseph's
17 ChurchStreet
18 Stourton
19 BalmRoad
20 BelleIsleNorth
21 BelleIsleCentral
22 BelleIsleSouth
23 MiddletonDistrictCentre
24 MiddletonCircus
25 Tingley
schedule
id_schedule id_tram id_stop routenr scheduletime
1 15 18 1 09:50:00
2 15 18 2 11:50:00
3 15 18 3 12:50:00
4 15 8 1 09:57:00
5 15 8 2 11:57:00
6 15 8 3 12:57:00
7 15 8 1 09:42:00
8 14 18 1 09:49:00
9 14 8 2 11:42:00
10 14 18 2 11:49:00
You could use this:
select tmp.routenr, maintable.stopname, maintable.scheduletime
from(
SELECT sc.routenr, st.stopname, sc.scheduletime
FROM schedule sc
INNER JOIN stops st
ON sc.id_stop = st.id_stop
INNER JOIN tram tr
ON sc.id_tram = tr.id_tram
WHERE tr.id_direction = '5' AND st.stopname = 'Stourton' AND
sc.scheduletime >= ('10:50:00')
OR tr.id_direction = '5' AND st.stopname = 'CitySquare'
) maintable
inner join (
SELECT sc1.routenr, count(*) as routenr_count
FROM schedule sc1
INNER JOIN stops st1
ON sc1.id_stop = st1.id_stop
INNER JOIN tram
ON sc1.id_tram = tr1.id_tram
WHERE tr1.id_direction = '5' AND st1.stopname = 'Stourton' AND
sc1.scheduletime >= ('10:50:00')
OR tr1.id_direction = '5' AND st1.stopname = 'CitySquare'
group by sc1.routenr
) tmp
on tmp.routenr = maintable.routenr
where tmp.routenr_count > 1
ORDER BY maintable.routenr ASC, maintable.scheduletime ASC;
I wonder about or clause, could you confirm it is right? Because i think it should be something like
where (tram.id_direction = '5' AND stops.stopname = 'Stourton' AND
schedule.scheduletime >= ('10:50:00')
)
OR
(tram.id_direction = '5' AND stops.stopname = 'CitySquare'
)
Editted: Changed so it work as your sample data. Another solution should be 2nd solution route_nr in (...) from Gordon Linoff (correct your intention of OR in his query first)
Perhaps it will be good enough to put the records for each route_nr on a single row. If so:
SELECT s.routenr, GROUP_CONCAT(st.stopname ORDER BY s.scheduletime) as stopnames,
GROUP_CONCAT(s.scheduletime ORDER BY s.scheduletime) as schedules
FROM schedule s INNER JOIN
stops st
ON s.id_stop = st.id_stop INNER JOIN
tram t
ON s.id_tram = t.id_tram
WHERE (t.id_direction = '5' AND st.stopname = 'Stourton' AND
s.scheduletime >= '10:50:00') OR
(t.id_direction = '5' AND st.stopname = 'CitySquare')
GROUP BY s.routenr
HAVING COUNT(*) > 1;
If you actually want the original rows, then you need a more complicated query that is cumbersome in MySQL (but not in other databases). One way is to repeat the logic of the outer query:
SELECT s.routenr, st.stopname, s.scheduletime
FROM schedule s INNER JOIN
stops st
ON s.id_stop = st.id_stop INNER JOIN
tram t
ON s.id_tram = t.id_tram
WHERE ((t.id_direction = '5' AND st.stopname = 'Stourton' AND
s.scheduletime >= '10:50:00') OR
(t.id_direction = '5' AND st.stopname = 'CitySquare')
) AND
s.routenr IN (SELECT s.routenr
FROM schedule s INNER JOIN
stops st
ON s.id_stop = st.id_stop INNER JOIN
tram t
ON s.id_tram = t.id_tram
WHERE (t.id_direction = '5' AND st.stopname = 'Stourton' AND s.scheduletime >= '10:50:00') OR
(t.id_direction = '5' AND st.stopname = 'CitySquare')
GROUP BY s.routenr
HAVING COUNT(*) > 1
);
SELECT schedule.routenr, stops.stopname, schedule.scheduletime FROM schedule
INNER JOIN stops ON
schedule.id_stop=stops.id_stop
INNER JOIN tram ON
schedule.id_tram=tram.id_tram
WHERE tram.id_direction = '5' AND stops.stopname = 'Stourton' AND
schedule.scheduletime >= ('10:50:00') OR tram.id_direction = '5' AND
stops.stopname = 'CitySquare' AND schedule.routenr
in (SELECT s.routenr FROM schedule s
INNER JOIN stops ON
schedule.id_stop=stops.id_stop
INNER JOIN tram ON
schedule.id_tram=tram.id_tram
WHERE tram.id_direction = '5' AND stops.stopname = 'Stourton' AND
schedule.scheduletime >= ('10:50:00')
OR tram.id_direction = '5' AND stops.stopname = 'CitySquare'
GROUP BY s.routenr
HAVING COUNT(*) > 1);
Another way to solve this problem is to simulate row_number using variables to enumerate the rows in each route_nr group by schedule_time in both ascending and descending order. All rows where one of the row numbers is greater than 1 are part of a route_nr group with more than 1 row:
SELECT * FROM (
SELECT * ,
#prevc2 := IF(#prev2 = routenr, #prevc2+1, 1) rn2,
#prev2 := routenr
FROM (
SELECT schedule.routenr, stops.stopname, schedule.scheduletime,
#prevc1 := IF(#prev1 = schedule.routenr, #prevc1+1, 1) rn1,
#prev1 := schedule.routenr
FROM schedule
INNER JOIN stops ON
schedule.id_stop=stops.id_stop
INNER JOIN tram ON
schedule.id_tram=tram.id_tram
WHERE tram.id_direction = '5' AND stops.stopname = 'Stourton' AND
schedule.scheduletime >= ('10:50:00')
OR tram.id_direction = '5' AND stops.stopname = 'CitySquare'
ORDER BY schedule.routenr ASC, schedule.scheduletime ASC
) t
ORDER BY routenr ASC, scheduletime DESC
) t WHERE rn1 > 1 OR rn2 > 1
I'm trying to get a set of values from a pivot table where column A is equal to an array of values, so for example ID 12 has attribute_value_id equal to 3 and 9. Can this be done? I've got this far...
ID | post_id | attribute_id | attribute_value_id
8 12 1 3
9 12 2 13
10 13 1 3
11 13 2 9
12 16 1 3
13 16 2 9
88 11 1 1
89 11 2 8
90 11 3 18
91 11 4 22
The query...
select *
from `searching_for_posts`
where (
select count(*)
from `attributes`
inner join `searching_for_attributes`
on `attributes`.`id` = `searching_for_attributes`.`attribute_id`
where `searching_for_attributes`.`searching_for_post_id` = `searching_for_posts`.`id`
and (`attribute_value_id` = 3 and `attribute_value_id` = 9)
) >= 1
If I use the and then I get no values. If I use the or then I get 3 values but it should return 2. I have limited SQL experience.
You can do this using group by and having. Your logic is hard to follow, but it is something like this:
select post_id
from table t
where attribute_value_id in (3, 9)
group by post_id
having count(distinct attribute_id) = 2;
I would think you would want to check on attribute_id as well, but that doesn't seem to be part of the question.
EDIT:
If these are stored in another table:
select a.post_id
from attributes a join
searching_for_attributes sfa
on a.attribute_id = sfa.attribute_id and
a.attribute_value_id = sfa.attribute_value_id
group by a.post_id
having count(*) = (select count(*) from searching_for_attributes);
In response to #GordonLinoff answer, I've managed to use GROUP BY and HAVING COUNT to get the desired data. Here's what I came up with and hope this helps someone else...
select *
from `searching_for_posts`
where (
select count(*)
from `attributes`
inner join `searching_for_attributes` on `attributes`.`id` = `searching_for_attributes`.`attribute_id`
where `searching_for_attributes`.`searching_for_post_id` = `searching_for_posts`.`id`
and `attribute_value_id` in (3, 9)
having count(distinct `attributes`.`id`) = 2
) >= 1
group by `id`
I've a following 3 table in mysql db.
project table :
p_id p_name p_notes is_active p_owner p_owner_id p_date
8 project notes 1 shibbir 18 01-01-2015
Project_assign_clients:
pac_id assign_clients assign_client_id is_main_user p_id
39 Hara Adachi 8725 1 8
40 Aihara 8726 0 8
41 Akanuma Kenji 8023 0 8
42 Bayani Patrick 7801 0 8
Project_assign_users:
pas_id assign_users assign_user_id p_id
5 teustace 12 8
6 alawson 10 8
7 mfischer 14 8
8 smitchell 15 8
Now I want to get how many projects users created. e.g. I have logged in user who's id is 18 so using above table it's should be return 1 project using mysqli_num_rows. here is my query but it's return 30 strange !!
$logged_user_id = $_SESSION['user_id'];
$query = mysqli_query($link, "SELECT projects . *, projects_assign_clients . *, projects_assign_users . * FROM projects LEFT JOIN projects_assign_clients on projects.p_id = projects_assign_clients.p_id LEFT JOIN projects_assign_users ON projects.p_id = projects_assign_users.p_id WHERE projects.p_owner_id = '$logged_user_id' ");
$num = mysqli_num_rows($query);
echo $num . " found"; // retrun 30 but should be 1 according to above table data
Just keep your query, but also add a sub-select to get the number of projects:
SELECT projects.*,
projects_assign_clients.*,
projects_assign_users.*,
(select count(*) from projects where p_owner_id = p.p_owner_id)
FROM projects p LEFT JOIN projects_assign_clients
ON projects.p_id = projects_assign_clients.p_id
LEFT JOIN projects_assign_users ON projects.p_id = projects_assign_users.p_id
WHERE projects.p_owner_id = '$logged_user_id'