MySQL table order by values from relation table by newest date - mysql

Is it possible to select from mySQL table rows ordered by joined table values by current date?
Maybe I show it. I Have two tables:
One country have many scores GROUPED BY date. Is it possible to sort countries by current date scores?
I have countires with scores from table in PHP arrays:
$countries = array(
'England' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-07', 'score' => 100),
1 => array('date' => '2018-08', 'score' => 50)
)),
'USA' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-08', 'score' => 50),
1 => array('date' => '2018-09', 'score' => 20)
)
),
'France' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-08', 'score' => 30),
1 => array('date' => '2018-09', 'score' => 100)
)
)
);
I need to select countries ordered by scores for current date. Lets say current date is 2018-09. I need to search countries and sort them like this:
$countries = array(
'France' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-08', 'score' => 30),
1 => array('date' => '2018-09', 'score' => 100)
)
),
'USA' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-08', 'score' => 50),
1 => array('date' => '2018-09', 'score' => 20)
)
),
'England' =>
array('name', 'tag',
'scores' => array(
0 => array('date' => '2018-07', 'score' => 100),
1 => array('date' => '2018-08', 'score' => 50)
)),
);
England is last becouse havent scores for date '2018-09'
Second is France becouse for date '2018-09' have 100 points
USA is last becosue for date '2018-09' have 20 points
SELECT c.name, s.date, s.score FROM country c LEFT JOIN score s ON s.country_id=c.id GROUP BY date ORDER BY (??)

We could do something like this, to get the latest score date for each country_id, along with the score for that latest date, and then order by those values:
SELECT c.name
, s.date
, s.score
FROM country c
LEFT
JOIN score s
ON s.country_id = c.id
LEFT
JOIN ( SELECT m.country_id
, MAX(m.date) AS max_date
FROM score m
GROUP
BY m.country_id
) n
ON n.country_id = c.id
LEFT
JOIN score o
ON o.country_id = n.country_id
AND o.date = n.max_date
ORDER
BY o.date DESC
, o.score DESC
, c.name ASC
, s.date ASC
Note that this assumes that the (country_id,date) tuple is unique in the score table. If we don't have that guarantee, we can tweak the query to accommodate that. Something like this:
SELECT c.name
, s.date
, s.score
FROM country c
LEFT
JOIN score s
ON s.country_id = c.id
LEFT
JOIN ( SELECT o.country_id
, o.date
, MAX(o.score) AS max_date_score
FROM ( SELECT m.country_id
, MAX(m.date) AS max_date
FROM score m
GROUP
BY m.country_id
) n
JOIN score o
ON o.country_id = n.country_id
AND o.date = n.max_date
GROUP
BY o.country_id
, o.date
) p
ON p.country_id = c.id
ORDER
BY p.date DESC
, p.max_date_score DESC
, c.name ASC
, s.date ASC
, s.score DESC

Related

How to merge 2 column into 1 column TO output in SQL

I have this sql query:
$sql = "SELECT d.doctor_name, a.patient_name, s.date, s.time FROM appointments AS a LEFT JOIN doctors AS d ON d.id = a.doctor_id LEFT JOIN slots AS s ON s.id = a.slot_id WHERE s.date > '2019-10-01' ORDER BY d.doctor_name DESC ";
$result = $mysqli->query($sql);
echo '<pre>';
while ( $row = $result->fetch_assoc() ) {
print_r($row);
}
echo '</pre>';
and it's output is:
Array
(
[doctor_name] => Khaled
[patient_name] => Nawaz
[date] => 2019-10-11
[time] => 02:01
)
Array
(
[doctor_name] => Khaled
[patient_name] => Anik
[date] => 2019-10-07
[time] => 02:31
)
Array
(
[doctor_name] => Khaled
[patient_name] => Manik
[date] => 2019-10-02
[time] => 03:31
)
Can I merge the date and time column as slot_date_time?
So output will be e.g:
Array
(
[doctor_name] => Khaled
[patient_name] => Manik
[slot_date_time] => 2019-10-02 03:31
)
Try this query
SELECT d.doctor_name, a.patient_name, CONCAT(s.date, ',', s.time) AS slot_date_time
FROM appointments AS a LEFT JOIN doctors AS d
ON d.id = a.doctor_id LEFT JOIN slots AS s
ON s.id = a.slot_id
WHERE s.date > '2019-10-01'
ORDER BY d.doctor_name DESC
Use CONCAT for merge two column as one column

how to combine 2 sql queries to get 1 result

SELECT users.name, users.registrationdate, users.city, users.status
FROM users, referrals
WHERE users.username= referrals.referrals AND referrals.username='user_name'
SELECT adearning, reffearning
FROM earnings WHERE usersname='user_name33'
How can I combine these two queries as if first query condition doesn't match and doesn't run.. then the second query should run and return some value if condition match
Try this
$query1 = $this->db->query("SELECT users.name, users.registrationdate, users.city, users.status
FROM users, referrals
WHERE users.username = referrals.referrals AND referrals.username='user_name'")
$result1 = $query1->result_array();
$query2 = $this->db->query("SELECT adearning, reffearning FROM earnings WHERE usersname='user_name33' ")
$result2 = $query2->result_array();
$dataArray = array_merge($result1, $result2);
if want to check the result, end of the line add this
print_r($dataArray);die;
On this it will print all of them in one array
Example
$result1 = array(
'0' => 'sjhccsd',
'1' => 'ddd',
'2' => 'df',
'3' => 'dfd',
);
$result2 = array(
'0' => 'sjhccsd',
'1' => 'ddd',
'2' => 'df',
'3' => 'dfd',
);
$dataArray = array_merge($result1, $result2);
print_r($dataArray);
Output : Array ( [0] => sjhccsd [1] => ddd [2] => df [3] => dfd [4] => sjhccsd [5] => ddd [6] => df [7] => dfd )

cakephp join from sorted and limited row

I have a working SQL query i want to figure out what would be the CakePHP query builder equivalent to work the exact same way?
SELECT customers.*, customer_reps.created FROM customers
LEFT JOIN customer_reps ON customer_reps.id =
(
SELECT id FROM customer_reps WHERE customer_id = customers.id
ORDER BY id ASC LIMIT 1
)
WHERE created >= 1475298000
AND created <= 1476217836
AND agents_id = 4
So essentially i am selecting all columns from "customers" and then i want only the "created" timestamp field of the FIRST "customer_reps" table for matching customer.
Documentation on CakePHP doesn't seem to explain how to do the select within select for sorting as this. I tried using the "hasMany" relational stuff but i was not able to find how to just get the "first" customer_reps entry to add to the main query for use in WHERE clause.
Thanks
try this code as a starting point you just need to group it by CustomerRep.customer_id because the order is already ascending if you're customer_reps table id is auto incremented already
$this->Customer->find('all', array(
'fields' => arrray(
'Customer.*',
'CustomerRep.created'
),
'joins' => array(
array(
'type' => 'LEFT',
'table' => 'customer_reps',
'alias' => 'CustomerRep',
'conditions' => 'Customer.id = CustomerRep.customer_id'
)
)
'conditions' => array(
'Customer.created >=' => '1475298000',
'Customer.created <=' => '1476217836',
'Customer.agentds_id' => 4
),
'group' => 'CustomerRep.customer_id'
));
Are you familiar with cakephp query builder? then if yes you should understand this flow
Step 1: SELECT customers.*, customer_reps.created FROM customers equivalent in cakephp is
$this->Customer->find('all', array(
'fields' => array(
'Customer.*',
'CustomerReply.created'
)
);
Note: CustomerReply.created is from join table of customer_reps which I just alias CustomerReply
Step 2: LEFT JOIN customer_reps ON customer_reps.id =
(
SELECT id FROM customer_reps WHERE customer_id = customers.id
ORDER BY id ASC LIMIT 1
) equivalent in cakephp is
'joins' => array(
array(
'table' => 'customer_reps',
'type' => 'left',
'alias' => 'CustomerReply',
'conditions' => array(
'CustomerReply.id = (SELECT id FROM customer_reps WHERE customer_id = Customer.id ORDER BY id ASC LIMIT 1)'
)
))
Step 3: WHERE created >= 1475298000
AND created <= 1476217836
AND agents_id = 4 equivalent in cakephp is
'conditions' => array(
'Customer.created >=' => 1475298000,
'Customer.created <=' => 1476217836,
'Customer.agents_id' => 4
)
);
so your cakephp query builder would be like this
$query = $this->Customer->find('all', array(
'fields' => array(
'Customer.*',
'CustomerReply.created'
),
'joins' => array(
array(
'table' => 'customer_reps',
'type' => 'left',
'alias' => 'CustomerReply',
'conditions' => array(
'CustomerReply.id = (SELECT id FROM customer_reps WHERE customer_id = Customer.id ORDER BY id ASC LIMIT 1)'
)
)),
'conditions' => array(
'Customer.created >=' => 1475298000,
'Customer.created <=' => 1476217836,
'Customer.agents_id' => 4
)
));

unread count and grouping

I have a very similar setup to this answer Is there a simpler way to achieve this style of user messaging?
However I'm having an issue with getting the total unread conversations and not unread messages.
SELECT p.conversation_id, COUNT(p.conversation_id) as unread
FROM participation AS p
INNER JOIN messages AS m
ON m.conversation_id = p.conversation_id AND m.seen = 0
WHERE p.uid1 = {$user->data['id']}
GROUP BY m.conversation_id`
I'm only selecting p.conversation_id for testing purposes, but the result I am getting is:
Array
(
[conversation_id] => 1
[unread] => 77
)
If I were to put the results in a PHP while loop I get
Array
(
[conversation_id] => 1
[unread] => 77
)
Array
(
[conversation_id] => 3
[unread] => 7
)
Array
(
[conversation_id] => 8
[unread] => 1
)
Array
(
[conversation_id] => 17
[unread] => 35
)
Array
(
[conversation_id] => 22
[unread] => 2
)
Array
(
[conversation_id] => 24
[unread] => 305
)
Array
(
[conversation_id] => 29
[unread] => 41
)
Array
(
[conversation_id] => 31
[unread] => 1
)
The result I am wanting is unread: 8
I think you just want conditional aggregation:
SELECT p.conversation_id,
SUM(m.seen = 0) as unseen,
SUM(m.seen <> 0) as seen
FROM participation AS p INNER JOIN
messages AS m
ON m.conversation_id = p.conversation_id AND m.seen = 0
WHERE p.uid1 = {$user->data['id']}
GROUP BY m.conversation_id
In addition, if you want the total over all conversations, leave out the group by.

MySQL Replace string SUM then total

Looking to get a total for each ID from the sum of the replacement fields.
SELECT
insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve,
SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve,
SUM(es_reserve+structure_reserve) AS total
FROM job_tbl
WHERE
job_status NOT IN(2,4,6,7,9) AND
insurance_carrier !=0 AND
FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND
FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW())
GROUP BY insurance_carrier
I get the results from es_reserve and structure_reserve but the total is 0.
BTW the fields contain items like $2,300- that's the reason for the replace
Any help would be appreciated!!!
EDIT: here is the results this produces
Array
(
[ID] => 14
[es_reserve] => 5000
[structure_reserve] => 35000
)
Array
(
[ID] => 15
[es_reserve] => 2500
[structure_reserve] => 2500
)
Array
(
[ID] => 41
[es_reserve] => 2500
[structure_reserve] => 2500
)
Array
(
[ID] => 44
[es_reserve] => 2500
[structure_reserve] =>
)
Here is what I would like it to produce
Array
(
[ID] => 14
[es_reserve] => 5000
[structure_reserve] => 35000
[total] => 40000
)
Array
(
[ID] => 15
[es_reserve] => 2500
[structure_reserve] => 2500
[total] => 5000
)
Array
(
[ID] => 41
[es_reserve] => 2500
[structure_reserve] => 2500
[total] => 5000
)
Array
(
[ID] => 44
[es_reserve] => 2500
[structure_reserve] =>
[total] => 2500
)
Total column is doing sum on original column value , the alias name defined in the select won't be used in the same select.
You can repeat replace statement while doing total column computation
SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')
+ REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))
Total,
instead of
SUM(es_reserve+structure_reserve) as total
The query becomes, with order by as asked in comment.
SELECT insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve, SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve, SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','') + REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-','')) as Total FROM job_tbl WHERE job_status NOT IN(2,4,6,7,9) AND insurance_carrier !=0 AND FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW()) GROUP BY insurance_carrier
order by SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','') + REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-','')) desc
OR
use it as subquery
SELECT T.*, SUM(es_reserve+structure_reserve) AS total
FROM
(
SELECT
insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve,
SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve
FROM job_tbl
WHERE
job_status NOT IN(2,4,6,7,9) AND
insurance_carrier !=0 AND
FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND
FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW())
GROUP BY insurance_carrier
) T