I have a table with values :
CREATE TABLE grade
(id int, name varchar(2), no int);
INSERT INTO grade
(id, name, no)
VALUES
(1, 'A', 7),
(2, 'B', 6),
(3, 'C', 10),
(4, 'D', 12),
(5, 'E', 15),
(6, 'F', 21),
(8, 'B', 16),
(7, 'F', 18),
(9, 'F', 25);
I need output in arrays to use.. i.e. :
[
['range','A','B','F'],
['0.00 - 4.41', 1, 1, 0],
['4.41 - 8.24', 0 , 1, 1]
...
...
['others', 0, 0, 1]
]
This is what I am tring (Fiddle) :
select range, array_agg(name) as name, array_agg(count) as count
from (
select case
when no between 0.00 and 4.41 then '0.00 - 4.41'
when no between 4.41 and 8.24 then '4.41 - 8.24'
when no between 8.24 and 14.77 then '8.24 - 14.77'
when no between 14.77 and 19.35 then '14.77 - 19.35'
when no between 19.35 and 23.00 then '19.35 - 23.00'
else 'Others' end as range, name, count (*) as count
from grade
WHERE name IN ('A','B','F')
group by range, name
order by name
) t
group by range
Is it possible to get desired output from db query only ? or I have use php to iterate through?
Found a way to archive result (Updated Fidddle):
select range, sum(a) as a_name,
sum(b) as b_name,
sum(f) as f_name,
sum(count) as total
from (
select case
when no between 0.00 and 4.41 then '0.00 - 4.41'
when no between 4.41 and 8.24 then '4.41 - 8.24'
when no between 8.24 and 14.77 then '8.24 - 14.77'
when no between 14.77 and 19.35 then '14.77 - 19.35'
when no between 19.35 and 23.00 then '19.35 - 23.00'
else 'Others' end as range,
count(name = 'A' OR NULL) as A,
count(name = 'B' OR NULL) as B,
count(name = 'F' OR NULL) as F,
count (*) as count
from grade
WHERE name IN ('A','B','F')
group by range, name
order by name
) t
group by range
Related
I'm trying to get all rows inside a foreach loop but it's not working as it should.
<?php
foreach ($locations_loop as $row):
$lr_id = $row["id"];
$stmtlr = $pdo->prepare("SELECT * FROM locations_rating WHERE l_id = {$lr_id}");
$stmtlr->execute();
$stlr_loop = $stmtlr->fetchAll(PDO::FETCH_ASSOC);
if (empty($stlr_loop)) {
$loc_rate[] = "0";
} else {
foreach($stlr_loop as $rowlr):
$loc_rate[] = $rowlr["stars"];
endforeach;
}
$rating_array = array_values($loc_rate);
$rating_avg = array_sum($rating_array) / count($rating_array);
?>
<?=round($rating_avg, 1);?>
<?php endforeach; ?>
$rating_avg outputs something else every time the script runs. It works fine outside a foreach loop tho. I tried to join the two table but no luck since it only outputs only one row.
I might be thinking too far out of the box, but this is just one technique that occurred to me which will ensure that all location ids will receive an average value in the result set.
Assuming $locations_loop (a poor name for a variable containing array type data, tbh) has the following data:
$locations_loop = [
['id' => 1],
['id' => 2],
['id' => 3],
['id' => 4],
];
And you have a database table with the following schema: (db-fiddle demo)
CREATE TABLE `locations_rating` (
`id` int(11) NOT NULL,
`l_id` int(11) NOT NULL,
`stars` int(11) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `locations_rating` (`id`, `l_id`, `stars`) VALUES
(1, 3, 4),
(2, 2, 2),
(3, 1, 0),
(4, 2, 5),
(5, 3, 2),
(6, 1, 10);
Then you can get all of your data in one trip to the database by creating a "derived table" from your column of id values, then joining the database data to them. Something like this:
SELECT def.l_id,
ROUND(AVG(COALESCE(stars, 0)), 1) avg
FROM (
(SELECT 1 AS l_id)
UNION (SELECT 2)
UNION (SELECT 3)
UNION (SELECT 4)
) AS def
LEFT JOIN locations_rating AS loc ON def.l_id = loc.l_id
GROUP BY def.l_id
To do this with a prepared statement and bound parameters:
$locationIds = array_column($locations_loop, 'id');
$countIds = count($locationIds);
$fabricatedRows = implode(' UNION ', array_fill(0, $countIds, '(SELECT ? AS l_id)'));
$sql = "SELECT derived.l_id,
ROUND(AVG(COALESCE(stars, 0)), 1) avg
($fabricatedRows) AS derived
LEFT JOIN locations_rating as loc ON derived.l_id = loc.l_id
GROUP BY def.l_id";
$stmt = $pdo->prepare($sql);
$stmt->execute($locationIds);
var_export($stmt->fetchAll(PDO::FETCH_ASSOC));
Should output: (I tested this technique to be successful in my local environment)
[
['l_id' => 1, 'avg' => 5.0],
['l_id' => 2, 'avg' => 3.5],
['l_id' => 3, 'avg' => 3.0],
['l_id' => 4, 'avg' => 0.0],
]
I need to write a script which takes a set of numeric values, for example: "1", "2" and "3" (the total number of values could be limitless)
And return the total of every combination, up to a given total, i.e. 5, therefore the return would look something like:
(1),
(2),
(3),
(1, 1),
(1, 1, 1),
(1, 1, 1, 1),
(1, 1, 1, 1, 1),
(1, 1, 1, 2),
(1, 2, 2)
....
What is the most efficient way to do this in PHP?
Thanks in advance.
I have two tables:
CampaignTable
which has following property
id , campaign ,user_group
example would be
1 8867116213 5,11,15,16,18,20
2 8867116214 0,8,22
Then I have another table called User Table
with following property
id emp_id user_group
Example is like this
1 274 0,5,8,9,10,11,21,20
2 275 5,11,20
3 279 19,21,22,25
I have to join this table and create an Array which has campaign wise user
for example for campaign with id 1 it should give me
274, 275
How can I achieve this in Mysql
Thanks
You should definetely normalize your data. For example consider this kind of normalization which renders almost no change to your DB structure:
INSERT INTO CampaignTable
(`campaign`, `user_group`)
VALUES
(8867116213, 5),
(8867116213, 11),
(8867116213, 15),
(8867116213, 16),
(8867116213, 18),
(8867116213, 20),
(8867116214, 0),
(8867116214, 8),
(8867116214, 22)
;
INSERT INTO UserTable
(`emp_id`, `user_group`)
VALUES
(274, 0),
(274, 5),
(274, 8),
(274, 9),
(274, 10),
(274, 11),
(274, 21),
(274, 20),
(275, 5),
(275, 11),
(275, 20),
(279, 19),
(279, 21),
(279, 22),
(279, 25)
;
You could then fetch your data with a query as simple as that:
SELECT c.campaign, GROUP_CONCAT(DISTINCT u.emp_id) FROM CampaignTable c
JOIN UserTable u ON c.user_group = u.user_group
GROUP BY c.campaign
See SQLFiddle
I have a query which is supposed to select the lowest price_per_pax_after_tax from every backend_hotels_id date_start and package_supplier and this appears to be working until I add a WHERE clause.
Here's the query:
SELECT e.price_per_pax_after_tax, e.hotel_score, e.package_id, e.package_type
FROM packages_sorted_YQU e
INNER JOIN (
SELECT db_id, MIN( price_per_pax_after_tax ) AS lowest_price, package_id, hotel_score
FROM `packages_sorted_YQU`
WHERE `package_type` IN ('9', '10', '18')
AND `package_duration` IN ('6', '8', '12')
GROUP BY
`date_start` , `package_supplier` , `backend_hotels_id`
) AS j
ON j.db_id = e.db_id
AND j.lowest_price= e.price_per_pax_after_tax
AND j.hotel_score = e.hotel_score
AND j.package_id = e.package_id;
The table is huge but all of the fields listed are INT except for date_start which is DATE
The where clause causing the problem is:
WHERE `package_type` IN ('9', '10', '18')
AND `package_duration` IN ('6', '8', '12')
Without the where clause I get over 400 results and with the where clause I get zero results :( Any help will be very much appreciated.
If your columns package_type and package_duration are of type int you don't have to wrap the values inside ' like strings.
SELECT e.price_per_pax_after_tax, e.hotel_score, e.package_id, e.package_type
FROM packages_sorted_YQU e
INNER JOIN (
SELECT db_id, MIN( price_per_pax_after_tax ) AS lowest_price, package_id, hotel_score
FROM `packages_sorted_YQU`
WHERE `package_type` IN (9, 10, 18)
AND `package_duration` IN (6, 8, 12)
GROUP BY
`date_start` , `package_supplier` , `backend_hotels_id`
) AS j
ON j.db_id = e.db_id
AND j.lowest_price= e.price_per_pax_after_tax
AND j.hotel_score = e.hotel_score
AND j.package_id = e.package_id;
The subquery:
SELECT db_id
, MIN( price_per_pax_after_tax ) AS lowest_price
, package_id
, hotel_score
FROM `packages_sorted_YQU`
WHERE `package_type` IN ('9', '10', '18')
AND `package_duration` IN ('6', '8', '12')
GROUP BY
`date_start`
, `package_supplier`
, `backend_hotels_id`
will yield indeterminate results, with or without the WHERE clause. Because you are grouping by date_start, package_supplier, backend_hotels_id and have in the SELECT list columns without any aggregate functions on them: db_id, package_id, hotel_score.
This query should work consistently if the (date_start, package_supplier, backend_hotels_id) is the Primary Key or Unique.
Which is the PRIMARY KEY of the table and are there any other UNIQUE keys?
Hi all and thank you for your valuable input. I've solved the problem without a sub-query and it works a bit faster too.
SELECT MIN
(
concat
(
LPAD(`price_per_pax_after_tax` , 5, '0'),
LPAD(`package_id` , 12, '0'),
LPAD(`hotel_score` , 7, '0')
)
) AS cat
FROM `packages_sorted_YQU`
WHERE `package_type` IN
(
9, 10, 18
)
AND `package_duration` IN
(
6, 7, 8
)
GROUP BY `date_start` , `package_supplier` , `backend_hotels_id`
Then in PHP I break apart the concatenation with:
while($r=mysql_fetch_array($q,MYSQL_ASSOC))
{
$a[lrp][] = intval(substr($r[cat], 0, 5));
$a[package_id][] = intval(substr($r[cat], 5, 12));
$a[hotel_score][] = substr($r[cat], 17, 7);
}
I was lucky that the only FLOAT value was the hotel_score so I put that last - the other two were of type INT
I have two MySQL tables with a similar structure. i.e.
Table_A - Col1, Col2, Col3, Col4, Col5
Table_B - Col1, Col2, Col3
I need to run a query that says something like:
SELECT * FROM Table_A WHERE (Table_A.Col1 DOES NOT EXISTS in Table_B.Col3 AND Table_B.Col2 = 'A') AND Table_A.Col5 = 2 etc...
So basically I need to select everything from A that isn't in B where B has extra conditions.
Hopefully the following example will help:
Table_A example rows
1, 5, 'Orange', 'Elephant', 1
2, 3, 'Red', 'Horse', 2
3, 4, 'Blue', 'Rhino', 2
4, 4, 'Pink', 'Cat', 2
5, 2, 'Purple', 'Dog', 2
Table_B example rows
1, 'A', 3
2, 'A', 2
3, 'B', 2
4, 'C', 3
The returned data I need is - I'm querying for all rows from Table_A that (aren't in Table_B AND Table_B.Col2 = 'A') AND Table_A.col5 = 2
4, 4, 'Pink', 'Cat', 2
5, 2, 'Purple', 'Dog', 2
Any ideas?
Thanks!
SELECT A.* FROM table_A AS A
LEFT JOIN Table_B AS B ON A.Col1 = B.Col3
WHERE B.Col3 IS NULL AND B.Col2 = 'A' AND ...