Mysql query, two tables. Select only if value exists in other table - php

I have two tables, options and products. I want to select all from options but only if options.id exists in any of the products columns. This are my two tables:
options table:
id option value
1 'kategorija' 'Muški'
2 'kategorija' 'Ženski'
3 'kategorija' 'Dječji'
4 'brand' 'Casio'
5 'brand' 'Lorus'
6 'brand' 'Seiko'
7 'brand' 'Citizen'
8 'mehanizam' 'Quartz'
9 'mehanizam' 'Automatik'
10 'mehanizam' 'Eco-Drive'
11 'brojcanik' 'Analogni'
12 'brojcanik' 'Digitalni'
13 'grupa' 'Satovi'
14 'grupa' 'Naocale'
and the second table products:
id grupa brand mehanizam brojcanik kategorija
10380 '13' '4' '8' '11' '2'
10560 '13' '4' '9' '12' '1'
11100 '13' '6' '8' '11' '2'
12380 '14' '7' '8' '11' '2'
12490 '13' '6' '9' '11' '1'
15720 '14' '6' '9' '12' '1'
16550 '14' '5' '8' '12' '3'
my attempt for query:
SELECT * FROM options WHERE EXISTS( SELECT 1 FROM products WHERE grupa="14" AND brand=options.id OR mehanizam=options.id OR brojcanik=options.id OR kategorija=options.id)
the result should be:
Array
(
[0] => Array
(
[id] => 14
[option] => grupa
[value] => Naocale
)
[1] => Array
(
[id] => 7
[option] => brand
[value] => Citizen
)
[2] => Array
(
[id] => 8
[option] => mehanizam
[value] => Quartz
)
[3] => Array
(
[id] => 11
[option] => brojcanik
[value] => Analogni
)
[4] => Array
(
[id] => 2
[option] => kategorija
[value] => Zenski
)
)
This is array only for one row for products id 12380 which is grupa 14. Array should go on for the rest of products where there is grupa 14 found in products row.
I don't know if this is possible only with mysql query. If it's not possible i will have to do comparison with php which is what I'm trying to avoid.
Thanks

Based on your statement,
I want to select all from options but only if options.id exists in any
of the products columns.
You can combine all values using UNION ALL in a subquery and join the result with table options.
SELECT DISTINCT a.*
FROM options a
INNER JOIN
(
SELECT brand col FROM products WHERE grupa = 14
UNION ALL
SELECT mehanizam col FROM products WHERE grupa = 14
UNION ALL
SELECT brojcanik col FROM products WHERE grupa = 14
UNION ALL
SELECT kategorija col FROM products WHERE grupa = 14
) b ON a.id = b.col
Much better way,
SELECT *
FROM options a
WHERE EXISTS
(
SELECT 1
FROM products b
WHERE b.grupa = '14' AND
a.ID IN (brand, mehanizam, brojcanik, kategorija)
)

Instead of using specifically 14 you can simply join on options again
WHERE EXISTS (SELECT 1 FROM products JOIN options ON id = grupa ...

Related

How to get the count of each category using group by?

I am using cakephp 2.0 framework. I want to count the number of records of each category.
Here i have two tables
eve_appointment_icons ->having columns- appointment_icon_id,appointment_icon_type_name
eve_appointments ->having columns- id, appointment_icon_id
I have fetch this data using this query:-
$this->EveAppointment->query("SELECT
a.appointment_type
d.appointment_icon_id,
a.appointment_icon_id ,
d.appointment_icon_type_name,
FROM eve_appointments a,
eve_appointment_icons d
WHERE a.appointment_type =1
AND d.appointment_icon_id = a.appointment_icon_id
UNION
SELECT
a.appointment_type
d.appointment_icon_id,
a.appointment_icon_id ,
d.appointment_icon_type_name,
FROM eve_appointments a,
eve_appointment_icons d
WHERE a.appointment_type =2
AND d.appointment_icon_id = a.appointment_icon_id
UNION
SELECT
a.appointment_type
d.appointment_icon_id,
a.appointment_icon_id ,
d.appointment_icon_type_name,
FROM eve_appointments a,
eve_appointment_icons d
WHERE a.appointment_type =3
AND d.appointment_icon_id = a.appointment_icon_id");
Here when I print this:
Array
(
[0] => Array
(
[appointment_icon_id] => 1
[appointment_icon_type_name] => Yoga
)
[1] => Array
(
[appointment_icon_id] => 1
[appointment_icon_type_name] => Yoga
)
[2] => Array
(
[appointment_icon_id] => 2
[appointment_icon_type_name] => Visit
)
[3] => Array
(
[appointment_icon_id] => 3
[appointment_icon_type_name] => Physio Therapy
)
[4] => Array
(
[appointment_icon_id] => 4
[appointment_icon_type_name] => Diagnostic
)
[5] => Array
(
[appointment_icon_id] => 4
[appointment_icon_type_name] => Diagnostic
)
[6] => Array
(
[appointment_icon_id] => 4
[appointment_icon_type_name] => Diagnostic
)
)
Now you can see the Yoga having appointment_icon_id is 1, visit having appointment_icon_id 2 and vice versa for others.
I want count of all these categories.
Like:
appointment_icon_type_name count
Yoga 2
Visit 1
Physio Therapy 1
Diagnostic 3
All you need is this:
select d.appointment_icon_type_name, count(*)
FROM eve_appointments a,
eve_appointment_icons d
WHERE d.appointment_icon_id = a.appointment_icon_id
group by d.appointment_icon_type_name

php group array results in single lines

Not sure if the title is appropriate for the question, but i have the following problem.
The following code:
while($row = mysql_fetch_array($result2)) {
print_r($row);
}
Produces the following result:
Array
(
[y] => 2016
[m] => 9
[status] => 0
[count] => 2
)
Array
(
[y] => 2016
[m] => 9
[status] => 1
[count] => 33
)
Array
(
[y] => 2016
[m] => 9
[status] => 2
[count] => 4
)
Array
(
[y] => 2016
[m] => 10
[status] => 0
[count] => 20
)
Array
(
[y] => 2016
[m] => 10
[status] => 1
[count] => 3
)
Array
(
[y] => 2016
[m] => 10
[status] => 2
[count] => 14
)
I would like some help with a function that would convert these results to the following format:
Array
(
[y] => 2016
[m] => 9
[<name status 0>] => 2
[<name status 1>] => 33
[<name status 2>] => 4
)
Array
(
[y] => 2016
[m] => 10
[<name status 0>] => 20
[<name status 1>] => 3
[<name status 2>] => 14
)
Any help is greatly appreciated.
This is my first post, so if this post misses important information .. please point it out, and i will add them.
Thank you in advance.
Edit:
The Mysql query:
SELECT y, m, count(status) as count, status
FROM (
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months) ym
LEFT JOIN db_orders
ON ym.y = YEAR(db_orders.delivery_date)
AND ym.m = MONTH(db_orders.delivery_date)
WHERE
(y=YEAR(CURDATE()) AND m<=MONTH(CURDATE()))
OR
(y<YEAR(CURDATE()) AND m>MONTH(CURDATE()))
GROUP BY y, m, status;
Edit 2:
The solution:
editing the select for the mysql query solved my problem:
SELECT y, m, COUNT(IF(status='0',1, NULL)) '', COUNT(IF(status='1',1, NULL)) '', COUNT(IF(status='2',1, NULL)) ''
This leads to the following query:
SELECT y, m, COUNT(IF(status='0',1, NULL)) '<name for status 0>', COUNT(IF(status='1',1, NULL)) '<name for status 1>', COUNT(IF(status='2',1, NULL)) '<name for status 2>'
FROM (
SELECT y, m
FROM
(SELECT YEAR(CURDATE()) y UNION ALL SELECT YEAR(CURDATE())-1) years,
(SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4
UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8
UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12) months) ym
LEFT JOIN db_orders
ON ym.y = YEAR(db_orders.delivery_date)
AND ym.m = MONTH(db_orders.delivery_date)
WHERE
(y=YEAR(CURDATE()) AND m<=MONTH(CURDATE()))
OR
(y<YEAR(CURDATE()) AND m>MONTH(CURDATE()))
GROUP BY y, m, status;

Order by not working with group by clause

I am using corequery of mysql in cakephp. I want the records in descending order. This is my table structure
enter code here
$coreQueryUser = $this->Message->query(
"select * from messages where messages.list_id = 3
group By (if(sender_id > reciever_id, sender_id, reciever_id)),
(if(sender_id > reciever_id, reciever_id, sender_id))
order by id desc
"
);
I want last message that belongs to (sender_id and reciver_id and viceversa) that belongs to list id 3
when i run this query i get the following output
<pre>Array
(
[0] => Array
(
[messages] => Array
(
[id] => 1
[sender_id] => 21
[reciever_id] => 10
[list_id] => 3
[message] => hello
[add_date] => 2016-09-25 00:00:00
[is_check] => 0
)
)
[1] => Array
(
[messages] => Array
(
[id] => 3
[sender_id] => 22
[reciever_id] => 10
[list_id] => 3
[message] => hello s
[add_date] => 2016-09-25 16:39:41
[is_check] => 0
)
)
)
but i wnat result like that:
Array
(
[0] => Array
(
[messages] => Array
(
[id] => 2
[sender_id] => 10
[reciever_id] => 21
[list_id] => 3
[message] => hello sir
[add_date] => 2016-09-25 00:00:00
[is_check] => 0
)
)
[1] => Array
(
[messages] => Array
(
[id] => 6
[sender_id] => 22
[reciever_id] => 10
[list_id] => 3
[message] => new
[add_date] => 2016-09-25 16:39:41
[is_check] => 0
)
)
)
Can anyone help me :(
The problem is that your query is against the sql standard because you have several fields in the select list that are neither in the group by list, nor are subject of an aggregate function, such as sum(). MySQL unfortunately allows such invalid queries to run under certain sql mode settings (the default settings of the most recent versions of MySQL would prevent such queries from running).
As MySQL documentation on group by clause says (bolding is mine):
If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard
SQL use of GROUP BY permits the select list, HAVING condition, or
ORDER BY list to refer to nonaggregated columns even if the columns
are not functionally dependent on GROUP BY columns. This causes MySQL
to accept the preceding query. In this case, the server is free to
choose any value from each group, so unless they are the same, the
values chosen are indeterminate, which is probably not what you want.
Furthermore, the selection of values from each group cannot be
influenced by adding an ORDER BY clause. Result set sorting occurs
after values have been chosen, and ORDER BY does not affect which
value within each group the server chooses.
You apparently want the latest record (with max(id) for each group. The proper way is to have a subquery that returns the max(id) per group and in the outer query join back to your main table using the ids to get the value of the other fields:
select m.*
from
messages m
inner join (
select max(id) as maxid
from messages
where messages.list_id = 3
group By (if(sender_id > reciever_id, sender_id, reciever_id)),
(if(sender_id > reciever_id, reciever_id, sender_id))
) t1 on m.id=t1.maxid
This code working:
SELECT * FROM generate_invoice
WHERE id IN
(
SELECT max(id) as id
FROM generate_invoice
GROUP by pay_id
ORDER by id DESC
)
How to group by DESC order
Try
SELECT * FROM ( SELECT * FROM generate_invoice ORDER BY id DESC ) AS g GROUP BY g.pay_id
OR
Use this code
SELECT m1.*,m2.* FROM generate_invoice m1 LEFT JOIN generate_invoice m2 ON (m1.pay_id = m2.pay_id AND m1.id < m2.id ) order by m1.id desc

multiple tables left join returns same value

Is it possible to make a query that will return one time the value of the second table and set the otherones at NULL. Im stuck with this.
This is my query
return $this->db->get_results(
"
SELECT id, name, type, check_in_days, check_out_days, all_check_out_days, minimum_stay, maximum_stay, all_accom, GROUP_CONCAT( accom_id ) as accom, GROUP_CONCAT( seasons_id ) as seasons, conditional_type
FROM $this->booking_rules_table
LEFT JOIN $this->booking_rules_accom_table
ON $this->booking_rules_table.id = $this->booking_rules_accom_table.rule_id
LEFT JOIN $this->booking_rules_seasons_table
ON $this->booking_rules_table.id = $this->booking_rules_seasons_table.rule_id
GROUP BY id
"
, ARRAY_A );
This returns a array like this
[2] => Array
(
[id] => 54
[name] =>
[type] => minimum_stay
[check_in_days] => 0,1,2,3,4,5,6
[check_out_days] => 0,1,2,3,4,5,6
[all_check_out_days] => 1
[minimum_stay] => 0
[maximum_stay] => 9999
[all_accom] => 0
[accom] => 7,7,7
[seasons] => 1,3,4
[conditional_type] => compulsory
)
You see that [accom] is returning the 7 3 times because the [seasons] has 3 values.
can i fix this with my query or is there an other solution. I dont want to explode it and build the array again.

Getting the most from a single MySQL query

I have a website that lists apartments that are available for rent. I have a few different tables in my MySQL database. One table is for basic information about the Apartment building as a whole, including address, ammenities, photos, an ID (NID), etc.
Another table lists the units available for rent within each building. So each apartment building has multiple floorplans, with a few studios, a few 1 bedroom units, sometimes a few 2 bedroom units, etc.
Currently I query my 'unit' table and ask for all units in a given apartment building. My query looks something like SELECT * FROM node_unit WHERE nid='555'
This might return something like the following:
NID Name Rent SqFT Bedrooms Bathrooms
555 Unit 1 $500 620 0 1
555 Unit 2 $550 680 0 1
555 Unit 3 $600 820 1 1
555 Unit 4 $650 920 1 1
555 Unit 5 $700 1220 2 1
555 Unit 6 $800 1420 2 2
555 Unit 7 $900 1500 3 2
555 Unit 8 $1100 1620 3 3
etc, etc
What I am then doing in my PHP is using an accordian to group the 1 bedrooms together, the 2 bedrooms together, etc.
Not all apartments have 2 bedrooms units, some only have 1 bedroom units, so I need to know within my PHP code if I should print another accordian.
Currently I am using multiple hits to the database to determine if a given building has any 2 bedroom units, if so print another row. Does this building have any 3 bedroom units? If so print another row, but I would like to stop hitting my database so much.
Finally, here is my question:
How can I store the results from my first DB call and somehow parse thru the data and and determine if a given NID has studios, 1 beds, 2 beds, etc? (I just started learning PHP/MySQL recently)
I would suggest a query like this:
SELECT * FROM node_unit WHERE nid='555'
ORDER BY Bedrooms ASC, Bathrooms ASC, Rent ASC
This would return your records ordered by # of bedrooms, # bathrooms, and rent amount (in that order).
You could easily store this in multidimensional array when reading from database like this (assuming mysqli use with result set stored in $result, but concept is same for other DB connection libraries)
$room_array = array();
while ($row = mysqli_fetch_assoc($result)) {
$room_array[(int)$row['Bedrooms']][] = $row;
}
You now have a multidimensional array with number of bedrooms as first index. The array might look like this if you var_dump it:
Array (
[0] => Array (
[0] => Array (
'NID' => '555',
'Name' => 'Unit 1',
'Rent' => '$500',
'SqFt' => '620',
'Bedrooms' => '0',
'Bathrooms' => '1',
)
[1] => Array (
'NID' => '555',
'Name' => 'Unit 2',
'Rent' => '$550',
'SqFt' => '680',
'Bedrooms' => '0',
'Bathrooms' => '1',
)
)
[1] => Array (
[0] => Array (
'NID' => '555',
'Name' => 'Unit 3',
'Rent' => '$600',
'SqFt' => '820',
'Bedrooms' => '1',
'Bathrooms' => '1',
)
[1] => Array (
'NID' => '555',
'Name' => 'Unit 4',
'Rent' => '$650',
'SqFt' => '920',
'Bedrooms' => '1',
'Bathrooms' => '1',
)
[2] => Array (
...
)
[3] => Array (
...
)
)
This makes it really easy to iterate over the number of bedrooms values in an outer loop, which creates your accordions, and then iterate the individual rooms in an inner loop.
foreach ($room_array as $num_bedrooms => $rooms) {
// start accordion
foreach ($rooms as $room) {
// output room details
}
// end accordion
}
All this would only require the single query.
Also make sure you have indexes on bedrooms, bathrooms, rent (or whichever you use in the sort) as well as on nid since it is used as the filter.
Try this as your database query, it will generate a row for each building for each unit type it has. You could also use it as a subquery and join to the parent table to get any other details you need about the building in one shot.
select 'studio' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 0 then 1 end) > 0
union all
select 'one bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 1 then 1 end) > 0
union all
select 'two bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 2 then 1 end) > 0
union all
select 'three bedroom' as unit_type, nid from node_unit group by nid having count(case when bedrooms = 3 then 1 end) > 0

Categories