I'd like to make PHP $where as part of big query. I need something like:
SELECT *
FROM rf2aq_eb_events
WHERE id
IN ( SELECT event_id
, SUM(number_registrants) summ
FROM rf2aq_eb_registrants
WHERE summ < event_capacity
);
The rf2aq_eb_events table looks like:
ID | event_capacity
1 | 7
2 | 5
3 | 9
The rf2aq_eb_registrants table:
ID | events_id | number_registrants
1 | 1 | 6
2 | 2 | 2
3 | 3 | 4
4 | 1 | 1
5 | 2 | 0
6 | 3 | 5
I need select events from the 'rf2aq_eb_events' for events with quantity of registrant < then event_capacity. There is event id = 2 respond the condition.
i've tried $where[] = 'a.id IN ( SELECT event_id FROM #__eb_registrants GROUP BY event_id HAVING sum(number_registrants) < a.event_capacity)';
It's working like SQL, but do not in php in the whole Query.
Below i've put php result.
SELECT a.id, a.title, a.location_id,
a.event_capacity, a.event_date, a.individual_price,
a.thumb, a.early_bird_discount_date, a.early_bird_discount_amount,
c.name AS location_name
FROM #__eb_events AS a
LEFT JOIN #__eb_locations AS c
ON a.location_id = c.id
WHERE a.published =1
AND DATE(event_date) between date(CURDATE() + INTERVAL 7 DAY)
and date(CURDATE() + INTERVAL 26 DAY)
AND (
cut_off_date = "0000-00-00 00:00:00"
OR DATE(cut_off_date) between NOW() and date(CURDATE() + INTERVAL 26 DAY)
) AND a.id IN (
SELECT event_id
FROM #__eb_registrants
GROUP BY event_id
HAVING sum(number_registrants) < a.event_capacity
) AND a.id IN (
SELECT event_id FROM #__eb_event_categories
WHERE category_id IN (6,7)
) AND a.access IN (1,1)
ORDER BY a.event_date
LIMIT 4
You don't have to use subqueries.
SELECT `e`.* FROM `rf2aq_eb_events` as `e`
LEFT JOIN `rf2aq_eb_registrants` as `r`
ON `r`.`events_id`=`e`.`ID`
GROUP BY `r`.`events_id`
HAVING SUM(`r`.`number_registrants `) < `e`.`event_capacity`
You can't use the result of an aggregate (e.g. SUM) in a WHERE you can use it in a HAVING but you need to do a GROUP BY in this case as well:
SELECT * FROM `rf2aq_eb_events` e
WHERE `id` IN (
SELECT `event_id`
FROM `rf2aq_eb_registrants` r
GROUP BY `event_id`
HAVING sum(`number_registrants`) < `event_capacity`
)
Related
I have three tables tbl_lead, tbl_documentsPickup and tbl_bankdata. In the tbl_lead table, I am inserting personal information. In the tbl_documentsPickup, I am inserting the document information which is more than one record for each user and In tbl_bankdata, Inserting the bank data which is more than one record for each user.
Now what I am doing is, I have to display the last record of each user from tbl_documentsPickup and tbl_bankdata. Also, there is a possibility that tbl_documentsPickup and tbl_bankdata can be empty for users.
tbl_lead
lead_id | name | email | mobile |
1 | qwsd |cm#gmail.com | 1111111111 |
2 | mjhd |qs#gmail.com | 2222222222 |
3 | oiuy |gh#gmail.com | 3333333333 |
4 | qswe |4e#gmail.com | 4444444444 |
tbl_documentsPickup
doc_id | lead_id| d_pickupStatus| d_date_of_created
1 | 1 | 1 | 2019-08-29 00:53:33
2 | 2 | 1 | 2019-08-29 12:40:14
3 | 1 | 2 | 2019-08-29 14:14:54
4 | 3 | 1 | 2019-08-29 14:26:22
5 | 3 | 3 | 2019-08-29 15:35:03
tbl_bankdata
bank_id |p_id| lead_id| d_fileStatus | date_of_added
1 | 1 | 1 | 1 | 2019-08-30 00:53:33
2 | 2 | 2 | 3 | 2019-08-30 12:40:14
3 | 3 | 1 | 4 | 2019-08-30 11:14:54
4 | 4 | 3 | 1 | 2019-08-30 12:26:22
5 | 5 | 3 | 2 | 2019-08-30 12:26:22
I am using below query but I am getting the error
You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near '' at line 1
$query="
SELECT * FROM tbl_lead
LEFT JOIN (
SELECT d.* FROM tbl_documentsPickup d
INNER JOIN (
SELECT lead_id, d_pickupStatus, MAX(d_date_of_created) AS maxdt_doc
FROM tbl_documentsPickup GROUP BY lead_id
) e ON d.`lead_id`=e.`lead_id` AND d.`d_date_of_created`=e.`maxdt_doc`
) as tbl_document
LEFT JOIN (
select lead_id, b_bankDoneStatus, max(date_of_added) as latest
from tbl_bankdata group by lead_id HAVING max(`date_of_added`) = latest
) r on tbl_lead.lead_id=r.lead_id";
$getQuery= $this->db->query($query);
return $getQuery->result();
You can approach this with correlated subqueries in the on clause of the left joins, as follows:
select l.*, d.*, b.*
from
tbl_lead l
left join tbl_documentsPickup d
on d.lead_id = l.lead_id
and d.d_date_of_created = (
select max(d_date_of_created)
from tbl_documentsPickup d1
where d1.lead_id = d.lead_id
)
left join tbl_bankdata b
on b.lead_id = l.lead_id
and d.date_of_added = (
select max(date_of_added)
from tbl_bankdata b1
where b1.lead_id = b.lead_id
)
For performance, you want indexes on:
tbl_documentsPickup(lead_id, d_date_of_created)
tbl_bankdata(lead_id, date_of_added)
In MariaDB 10.2 or higher, another option is to use window functions:
select l.*, d.*, b.*
from
tbl_lead l
left join
(
select
d.*,
row_number() over(partition by lead_id order by d_date_of_created desc) rn
from tbl_documentsPickup d
) d on d.lead_id = l.lead_id and d.rn = 1
left join
(
select
b.*,
row_number() over(partition by lead_id order by date_of_added desc) rn
from tbl_bankdata b
) b on b.lead_id = l.lead_id and b.rn = 1
This is your query. (I've removed the superfluous backticks.)
SELECT *
FROM tbl_lead
LEFT JOIN
(
SELECT d.*
FROM tbl_documentsPickup d
INNER JOIN
(
SELECT lead_id, d_pickupStatus, MAX(d_date_of_created) AS maxdt_doc
FROM tbl_documentsPickup
GROUP BY lead_id
) e ON d.lead_id = e.lead_id AND d.d_date_of_created = e.maxdt_doc
) as tbl_document
LEFT JOIN
(
select lead_id, b_bankDoneStatus, max(date_of_added) as latest
from tbl_bankdata
group by lead_id
HAVING max(date_of_added) = latest
) r on tbl_lead.lead_id = r.lead_id;
Here are the things you are doing wrong:
You are selecting d_pickupStatus in your e subquery. But as you are grouping by lead_id only, you get one d_pickupStatus per lead_id arbitrarily picked. That doesn't seem to make much sense.
You left outer join tbl_document, but there is no join condition. You are missing the ON clause. That should be the syntax error you are seeing, I guess.
Your r subquery makes no sense at all to me. First you are selecting an arbitrarily picked value again (b_bankDoneStatus). And then you use a HAVING clause where you say that a value shall match itself. (latest is your alias name for max(date_of_added), so max(date_of_added) = latest is always true.)
Here is one way to get the last entries per lead_id from tbl_documentspickup and tbl_bankdata.
select *
from tbl_lead
left join
(
select *
from tbl_documentspickup
where (lead_id, d_date_of_created) in
(
select lead_id, max(d_date_of_created)
from tbl_documentspickup
group by lead_id
)
) latest_documentspickup using (lead_id)
left join
(
select *
from tbl_bankdata
where (lead_id, date_of_added) in
(
select lead_id, max(date_of_added)
from tbl_bankdata
group by lead_id
)
) latest_bankdata using (lead_id)
order by lead_id;
I need to find the period without pause in days since last pause.
I have a next table:
id | user | date
-----------------------
1 | 1 | 16.02.2017
1 | 1 | 15.02.2017
1 | 1 | 14.02.2017
1 | 1 | 13.02.2017
1 | 1 | 10.02.2017
Last pause: 10-13 February
Last period without pause: 4 days
I tried to found the difference between day like in this question, but as result it was always NULL. And this is only first part. For second part I thought to use something like ranking, but don't know if it will work.
I plan to use it with PHP 7 + MySQL 5.6.
I've used this sample:
create table if not exists myt(id int, dd date);
insert into myt values
(1, '2017-01-01'),
(1, '2017-01-02'),
(1, '2017-01-03'),
(1, '2017-01-04'),
(1, '2017-01-08'),
(1, '2017-01-09'),
(1, '2017-01-10');
First you should set a partition by consecutive days:
select id, dd,
if(#last_date = '1900-01-01' or datediff(dd, #last_date) = -1, #cn := #cn, #cn := +1) consecutive,
#last_date := dd
from
(select #last_date := '1900-01-01', #cn := 0) x,
(select id, dd
from myt
order by dd desc) y
;
This returns:
+----+---------------------+-------------+
| id | dd | consecutive |
+----+---------------------+-------------+
| 1 | 10.01.2017 00:00:00 | 0 |
| 1 | 09.01.2017 00:00:00 | 0 |
| 1 | 08.01.2017 00:00:00 | 0 |
+----+---------------------+-------------+
| 1 | 04.01.2017 00:00:00 | 1 |
| 1 | 03.01.2017 00:00:00 | 1 |
| 1 | 02.01.2017 00:00:00 | 1 |
| 1 | 01.01.2017 00:00:00 | 1 |
+----+---------------------+-------------+
After you set a partition, then get MAX and MIN date for each partition:
select id, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd)) as Days
from (
select id, dd,
if(#last_date = '1900-01-01' or datediff(dd, #last_date) = -1, #cn := #cn, #cn := +1) consecutive,
#last_date := dd
from
(select #last_date := '1900-01-01', #cn := 0) x,
(select id, dd
from myt
order by dd desc) y
) z
group by consecutive
;
Result:
+----+---------------------+---------------------+------+
| id | ini | fin | Days |
+----+---------------------+---------------------+------+
| 1 | 08.01.2017 00:00:00 | 10.01.2017 00:00:00 | 2 |
+----+---------------------+---------------------+------+
| 1 | 01.01.2017 00:00:00 | 04.01.2017 00:00:00 | 3 |
+----+---------------------+---------------------+------+
Check it: http://rextester.com/XMIX80360
Try this query. It will find all pauses -
SELECT curr_date, prev_date FROM (
SELECT t1.date curr_date, MAX(t2.date) prev_date FROM periods t1
LEFT JOIN periods t2
ON t1.date > t2.date
GROUP BY t1.date) t
WHERE DATEDIFF(curr_date, prev_date) > 1
The result is:
13-Feb-17 10-Feb-17
Then add condition/LIMIT to get only one row.
I am trying to write general query like,
select count(distinct t1.`date`) from period t1 left join period t2 ON t2.user = t1.user and t1.`date` - INTERVAL 1 DAY = t2.date where t2.id is null
Can you try this query once,
it should work, I have used it in my almost same case.
This query will return the latest hole:
select
m.`date`,
min(m1.`date`) as next_date,
datediff(min(m1.`date`), m.`date`)+1 as diff
from
mytable m left join mytable m1
on m.`date`<m1.`date`
group by
m.`date`
having
datediff(min(m1.`date`), m.`date`)>1
order by
m.`date` desc
limit 1
The following query:
SELECT MIN(`date`) AS date_start,
MAX(`date`) AS date_end,
MAX(days_diff) AS pause_days,
COUNT(*) + 1 AS period_without_pays
FROM (
SELECT id, user, `date`,
DATE_SUB(`date`, INTERVAL rn DAY) AS group_date,
DATEDIFF(`date`, COALESCE(prevDate, `date`)) AS days_diff
FROM (
SELECT t1.id, t1.user, t1.`date`,
#rn := #rn + 1 AS rn,
(SELECT t2.`date`
FROM mytable AS t2
WHERE t1.id = t2.id AND t1.user = t2.user AND t1.`date` > t2.`date`
ORDER BY `date` DESC LIMIT 1) AS prevDate
FROM mytable AS t1
CROSS JOIN (SELECT #rn := 0) AS v
ORDER BY `date`) AS t) AS x
GROUP BY id, user, group_date, days_diff
HAVING SUM(days_diff) > 0
returns:
date_start date_end pause_days period_without_pays
-----------------------------------------------------
2017-02-14 2017-02-16 1 4
2017-02-13 2017-02-13 3 2
The row with pause_days > 1 returns the start date of the pause along with the number of days.
The row with pause_days = 1 returns the start / end dates of an island of consecutive records having consecutive dates along with the count of these dates.
Note: The above query works with the sample data provided. You may have to tweak the query a little bit so as to adjust it to the complexity of the actual data.
Try this one:
SET #dateDiff=NULL;SET #dateDiff2='';
SELECT diff.secondDate AS fromDate,diff.initialDate AS toDate, diff.dateDiffR FROM (
SELECT d.date AS initialDate,#dateDiff AS secondDate,IF(#dateDiff IS NULL,#dateDiff:=d.date,0) AS try,
IF(DATE(#dateDiff)!=DATE(d.date),DATEDIFF(d.date,#dateDiff),NULL) AS dateDiffR,
IF(#dateDiff!=#dateDiff2,#dateDiff2:=#dateDiff,0) AS try1,
IF(DATE(#dateDiff)!=DATE(d.date),#dateDiff:=d.date,NULL) AS assign FROM
(SELECT b.date FROM mytable b)d ) diff WHERE diff.dateDiffR>0
it will give you the date difference with its date range. If you get negative count then swap the dates on parameters' for DATEDIFF;
(Posted on behalf of the OP).
I adapted little bit query from #McNets:
select user, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd))+1 as Days, consecutive
from (
select user,dd,
if(#last_date = curdate() or datediff(dd, #last_date) >= -1, #cn := #cn, #cn := #cn+1) consecutive,
#last_date := dd
from
(select #last_date := curdate(), #cn := 0) x,
(select user, date as dd
from myt
where user = %id
order by dd desc) y
) z
group by consecutive
order by CAST(consecutive AS UNSIGNED)
I added filter by user, changed cause to '>= -1' to accept time usage, added number of the serie and changed initial date from '1900-01-01' to CURDATE() function (i don't see any influence to query result from this action).
Now using number of the series can find the longest series and its dates.
I have this tables :
Table: Articles
id | title | display |
-----------------------------------
1 | Fkekc | 1 |
2 | ldsdf | 1 |
3 | OTRld | 0 |
4 | QCRSA | 1 |
Table: Likes
id | article_id | like | type
----------------------------------------
1 | 1 | 121 | 1
2 | 1 | 652 | 2
3 | 2 | 12 | 1
4 | 1 | 5 | 3
i want get this result:
Article [1] => 778
Article [2] => 12
Article [3] => 0
Article [4] => 0
I use LEFT JOIN between two tables but this return records per likes table. so i get three record of article 1
My code:
SELECT articles.*,likes.like FROM `articles` LEFT JOIN `likes` ON articles.id=likes.article_id WHERE display='1'
I know that i must use SUM() but i didn't know how use it
With your answers i find that i must use this:
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' GROUP BY articles.id
But i want to set filter in query. so use this :
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' && likesSum>='100' GROUP BY articles.id
But above code doesn't return any result
This is your query
SELECT articles.*,COALESCE(sum(likes.like),0) as total_like FROM
`articles` LEFT JOIN `likes` ON articles.id=likes.article_id group by
articles.id
Output is
SELECT articles.*, sum(likes.like) as likesSum FROM `articles` LEFT JOIN `likes`ON articles.id=likes.article_id WHERE display='1' GROUP BY articles.id
This should work for you perfectly..
SELECT articles.id, sum(likes.like) from articles left join likes on (articles.id=likes.article_id) group by articles.id order by articles.id
See the use of SUM() with GROUP BY
This visual representation is great to understand the joins: http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
You did everything right but only one this missing. You should have used group by
SELECT articles.*, likes.like
FROM `articles`
LEFT JOIN `likes` ON articles.id = likes.article_id
WHERE display = '1'
GROUP BY likes.article_id
I need advice.
I have a simple while loop.
And I have a table contestants. Each contestant has a total column [celkem].
These data excerpting the cycle while
And I need that when you have two points as well, so it was always in range (see picture)
The rest of excerpting something like this: $ row ['name']; $ row ['bodycelkem']
My question is, how to use PHP and MySQL dump this range order?
Edit:
SQLFiddler
(I need auto rank where point in range)
Because the Poradi info does not exist, you need to extrapolate it. You can do this with variables. See my SQL below or in the SQLFiddle
SELECT `range`, jmeno, rangeData.celkem FROM `hraci`
LEFT JOIN (
SELECT
a1.*,
if( range_start = range_end,
range_start, CONCAT(range_start,", - ",range_end)
) `range`
FROM (
SELECT
q1.*,
(#runtot + 1) AS range_start,
(#runtot := #runtot + q1.num) range_end
FROM (
SELECT #rn:=#rn+1 rank, t1.num, t1.celkem FROM (
SELECT celkem, count(celkem) num FROM hraci GROUP BY celkem ORDER BY celkem DESC
) t1, (SELECT #rn:=0) t2
) q1, (SELECT #runtot:=0) q2
) a1
) rangeData ON hraci.`celkem` = rangeData.`celkem`
How does this work?
Group the 'celkem' values together, descending. Keep an aggregate of how many 'celkem' values are in each group.
Add a row count to that data, using variables
Using variables again, keep a running total of the group sizes, which will give us the 'range end'. Taking the variable from the last run before incrementing it gives us the 'range start'
If the start and end is the same, just use the start. If the start and end is different, display both values
We now have the Poradi (range?). We can now proceed to just collect our data as normal, but now we can join the groups onto the names.
Neaten all the data up by just selecting the columns we want.
Here's one idea
DROP TABLE IF EXISTS hraci;
CREATE TABLE hraci (
jmeno VARCHAR(45) NULL,
celkem DOUBLE NULL)
ENGINE = InnoDB;
INSERT INTO hraci
(jmeno, celkem) VALUES
('Dan', 97.5),
('Adam', 97.2),
('Petr', 90.5),
('Pavel', 90.5),
('Michal', 87.3),
('Jan', 87.3),
('David', 87.3),
('Tomás', 87.3),
('Jarda', 85.2);
SELECT a.celkem
, a.jmeno
, CASE WHEN MIN(b.rank)-1 <> a.rank THEN CONCAT(a.rank,' - ',MIN(b.rank) - 1) ELSE a.rank END rank
FROM
( SELECT celkem
, jmeno
, FIND_IN_SET(celkem,celkems) rank
FROM hraci
CROSS
JOIN
( SELECT GROUP_CONCAT( celkem ORDER BY celkem DESC) celkems
FROM hraci
) x
) a
LEFT JOIN
( SELECT celkem
, jmeno
, FIND_IN_SET(celkem,celkems) rank
FROM hraci
CROSS
JOIN
( SELECT GROUP_CONCAT( celkem ORDER BY celkem DESC) celkems
FROM hraci
) y
) b
ON b.rank > a.rank
GROUP BY a.celkem,a.jmeno;
+--------+--------+-------+
| celkem | jmeno | rank |
+--------+--------+-------+
| 85.2 | Jarda | 9 |
| 87.3 | David | 5 - 8 |
| 87.3 | Jan | 5 - 8 |
| 87.3 | Michal | 5 - 8 |
| 87.3 | Tomás | 5 - 8 |
| 90.5 | Pavel | 3 - 4 |
| 90.5 | Petr | 3 - 4 |
| 97.2 | Adam | 2 |
| 97.5 | Dan | 1 |
+--------+--------+-------+
http://sqlfiddle.com/#!9/2a7a5/2
I have a simple table called users with the following data:
id | hops
1 | 3
2 | 1
3 | 5
4 | 2
5 | 6
6 | 5
I want to make a prev/next navigation according to hops sorted descending. I use the following to query to sort descending:
SELECT * FROM users ORDER BY hops DESC, id DESC
This is the result:
id | hops
5 | 6
6 | 5
3 | 5
1 | 3
4 | 2
2 | 1
Now what I want is that when I input any id in a mysql query I get the previous and next ids according to sorting above. For example:
For id 5 (In this case id=5 has the highest hops so no previous records before it):
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
5 | 6 | NULL | NULL | 6 | 5
For id 6:
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
6 | 5 | 5 | 6 | 3 | 5
For id 3:
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
3 | 5 | 6 | 5 | 1 | 3
For id 1:
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
1 | 3 | 3 | 5 | 4 | 2
For id 4:
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
4 | 2 | 1 | 3 | 2 | 1
For id 2 (In this case id=2 has the lowest hops so no next records after it)
id (current) | hops (current) | id (prev) | hops (prev) | id (next) | hops (next)
2 | 1 | 4 | 2 | NULL | NULL
Thanks
Try:
select cp.*, n.id id_next, n.hops hops_next
from
(select c.id id_current, c.hops hops_current, p.id id_previous, p.hops hops_previous
from
(select * from users where id = ?) c
left join users p on c.hops < p.hops or (c.id < p.id and c.hops = p.hops)
order by p.hops, p.id limit 1) cp
left join users n
on cp.hops_current > n.hops or (cp.id_current > n.id and cp.hops_current = n.hops)
order by n.hops desc, n.id desc limit 1
(SQLFiddle here)
This is the weirdest users table I've seen so far. Anyway here's one way (although I have to admit it's a little complicated)...
DROP TABLE IF EXISTS test;
CREATE TABLE test(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,hops INT NOT NULL);
INSERT INTO test VALUES
(1 ,3),(2 ,1),(3,5),(4 ,2),(5 ,6),(6 ,5);
SELECT c.id id_curr
, c.hops hops_curr
, p.id id_prev
, p.hops hops_prev
, n.id id_next
, n.hops hops_next
FROM
(
SELECT a.*
, COUNT(*) new_rank
FROM
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) a
JOIN
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) b
ON b.rank < a.rank
OR (b.rank = a.rank AND b.id >= a.id)
GROUP
BY a.id
)c
LEFT
JOIN
(
SELECT a.*
, COUNT(*) new_rank
FROM
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) a
JOIN
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) b
ON b.rank < a.rank
OR (b.rank = a.rank AND b.id >= a.id)
GROUP
BY a.id
) p
ON p.new_rank = c.new_rank-1
LEFT
JOIN
(
SELECT a.*
, COUNT(*) new_rank
FROM
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) a
JOIN
( SELECT x.*
, COUNT(*) rank
FROM test x
JOIN test y
ON y.hops >= x.hops
GROUP
BY x.id
) b
ON b.rank < a.rank
OR (b.rank = a.rank AND b.id >= a.id)
GROUP
BY a.id
) n
ON n.new_rank = c.new_rank+1
ORDER
BY c.hops DESC
, c.id DESC;