I have a start date and a end date.
$s="YYYY-MM-DD";
$e="YYYY-MM-DD";
I need to make a query that checks the available rooms for that span.
cObjects , cBookings_details
cObjects_id = cBookings_details_cObjects_id
Im really stuck here, would really appreciate some help.
My Current Query
SELECT cObjects.*
FROM cObjects LEFT JOIN cBookings_details ON cObjects.cObjects_id = cBookings_details.cBookings_details_cObjects_id
WHERE cBookings_details.cBookings_details_arrival NOT BETWEEN '".$s."' AND '".$e."'
AND cBookings_details.cBookings_details_departure NOT BETWEEN '".$s."' AND '".$e."'
AND cBookings_details.cBookings_details_arrival <> '".$s."' AND cBookings_details_departure <> '".$s."'
AND cBookings_details.cBookings_details_arrival <> '".$e."' AND cBookings_details_departure <> '".$e."'
AND cObjects.cObjects_type < '2'
OR cBookings_details.cBookings_details_id is null AND cObjects_type < '2'
This is a common problem.. actually just wrote a guide for this at work:
Selecting rows with start and end dates that feature in a chosen interval
-------------------------------------------------------------------------
Chosen Interval - :start_date (S)
:end_date (E)
Rows - row.start_date (s)
row.end_date (e)
Increasing date-->
S E
| | Chosen Interval
1. s---e Rows we want
2. s---e .
3. s---e .
4. s----------e .
5. s--e Rows we don't want
6. s--e .
LOGIC:
row.end_date >= :start_date AND row.start_date <= :end_date
If you are looking for available rooms, LEFT JOIN the room to the bookings using the logic above and SELECT rows where the booking is NULL.
Applied to your schema I believe this would come out as:
SELECT o.*
FROM cObjects o
LEFT JOIN cBookings_details bd
ON bd.cBookings_details_cObjects_id = o.cObjects_id
AND bd.cBookings_details_arrival <= :end_date
AND bd.cBookings_details_departure >= :start_date
WHERE bd.cBookings_details_id IS NULL
(AND o.cObjects_type < '2') # Double check this is what you want
By the way, I would cry if I had to work with your schema. Why repeat the table name in the column? It just adds noise.
Related
In attempting to calculate the longest goalscoring streak for a single player, I've hit a stumbling block with the >= PHP operator not performing as intended.
The data is presented in a table as follows:
date gls
------------------------
1980-08-16 2
1980-08-19 1
1980-08-23 1
1980-08-26 0
1980-08-30 1
1980-09-06 2
1980-09-13 0
... and so on
The PHP query I am using is as follows:
SELECT gls, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games
FROM (SELECT gls, date,
(SELECT COUNT(*)
FROM goalsengine G
WHERE G.gls <> GE.gls
AND G.date <= GE.date) as RunGroup
FROM goalsengine GE) A
WHERE gls>='1'
GROUP BY gls, RunGroup
ORDER BY Games
I formed the query this way in the belief that >= would tally up streaks where this player had scored one or more goals in a game. From the table above, the first three entries would represent a scoring run of three games, for example.
Instead, the query is returning streaks but only where a certain number of goals are scored i.e. despite scoring in the first three games, the first entry (where two goals were scored, not one) is ignored when the streak is returned.
To return the results, I am using the following:
while($row=mysql_fetch_assoc($result))
{
{$startrundate = date("d F Y",strtotime($row['StartDate']));}
{$endrundate = date("d F Y",strtotime($row['EndDate']));}
echo "<tr>";
echo "<td>".$row['Games']."</td>";
echo "<td class='tableprofile' style='text-align:right;'>".$startrundate." - ".$endrundate."</td>";
echo "</tr>";
$rowCount += 1;
}
By comparison, WHERE gls='0' is giving me the desired non-goalscoring streaks. I feel I have perhaps overlooked something straightforward but cannot see what.
I've managed to work out a solution to this particular issue and it works as far as I can tell, having counted some of the raw data out manually.
SELECT gls, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games
FROM (SELECT gls, date,
(SELECT COUNT(*)
FROM goalsengine G
WHERE IF(G.gls IN ('1','2','3','4','5'),1,0) <> IF(GE.gls IN ('1','2','3','4','5'),1,0)
AND G.date <= GE.date) as RunGroup
FROM goalsengine GE) A
WHERE gls IN ('1','2','3','4','5') GROUP BY IF(bg IN ('1','2','3','4','5'),1,0), RunGroup ORDER BY Games DESC LIMIT 3");
I admit it's not exactly pretty, but it's doing the job for now. I have gone to 5 in the calculation as that's the maximum number of goals scored in a single match with regards to this data set.
I have this query in MySQL. This query is taking too long to run, and I know the problem is the selectors (coalesce ((SELECT ...), I do not know how to speed up a query, via join.
I am hoping some of you SQL gurus will be able to help me.
SELECT
COALESCE(
(SELECT CONCAT(d.PRIJEVOZNIK, ' ', d.VOZAC_TRANSFER)
FROM dokum_zag as d
where d.SIFKNJ='NP' and
d.ID_VEZA=dokum_zag.ID and
d.korisnicko_ime=dokum_zag.korisnicko_ime
),'') as PRIJEVOZNIK,
(RELACIJA_TRANS_VOZ_TRANS) as RELACIJA_TRANS_VOZ,
(PRIJEVOZNIK_POVRATNI_TRANS) as PRIJEVOZNIK_POVRATNI,
(VAUC_KNJIZENO_TRANS) as VAUC_KNJIZENO,
ID_NALOGA,
ID_NALOGA_POV,
ID_VAUCHER,
DOLAZAK, VRIJ_TRANSFER,ODLAZAK,VRIJEME_LETA_POVRAT ,BRDOK, NOSITELJ_REZ, RELACIJA_TRANS, VOZILO_NAZIV, BROJ_NALOGA,BROJ_NAL_POV,BROJ_VAUCHER,BROJ_SOBE,VALIZN,PAX, MPIZN,ID
FROM
dokum_zag
WHERE
korisnicko_ime = '10' and
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
STORNO <> 'DA' and
SIFKNJ = 'TR' and
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
order by
(CASE WHEN DOLAZAK < '2015-07-30' THEN ODLAZAK ELSE DOLAZAK END) ,
(CASE WHEN DOLAZAK < '2015-07-30' THEN VRIJEME_LETA_POVRAT ELSE VRIJ_TRANSFER END), ID
Without a DB structure, and a description of what you want to extract it's a bit hard to help you.
From a logical point of view, somethings are redundant, for example
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
...
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
The year part isn't necessary since the year is specified on the first two.
Another thing that might be making the server nuts, is that weird order by clause, since it changes from record to record (test this setting it fixed on a field).
You can also check if your indexes are properly set for all the fields on the external where clause, and those which are not numeric, are not varchars (for example SIFKNJ and STORNO should be char(2) ).
The coalesce part can be solved via an outer join, so it doesn't get calculated on each row. But that depends on what and how you want to extract from the database... (since that subquery has it's own fields on the where section... weird)
Hope this somehow helps
INDEX(korisnicko_ime, SIFKNJ)
(in either order) may help
Turning the correlated subquery into a JOIN may help.
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
is a bit weird. This might help:
( SELECT ...
AND DOLAZAK ='2015-07-30' AND ODLAZAK >= '2015-01-01'
AND ODLAZAK < '2015-01-01' + INTERVAL 1 YEAR
) UNION DISTINCT
( SELECT ...
AND ODLAZAK ='2015-07-30' AND DOLAZAK >= '2015-01-01'
AND DOLAZAK < '2015-01-01' + INTERVAL 1 YEAR
) ORDER BY ...
To help that reformulation, add 2 composite indexes:
INDEX(korisnicko_ime, SIFKNJ, DOLAZAK, ODLAZAK)
INDEX(korisnicko_ime, SIFKNJ, ODLAZAK, DOLAZAK)
I am making a stats page about golf for the people I play with. I am trying to pull out of the database the number of times out of all our scorecards that we received birdies (which is -1 under par). It does pull out the -1s per hole, however I noticed that you if you had 2 birdies on a scorecard, it still only counts as 1 birdie instead of 2. I want it to keep counting, so if someone gets 9 birdies, those 9 are added to the total.
$query_p321 = "SELECT t1.*,COUNT(t1.player_id),t2.* FROM scorecards t1 LEFT JOIN courses t2 ON t1.course_id=t2.course_id
WHERE t1.hole1<t2.hole1_par AND t1.hole1>t2.hole1_par-2
OR t1.hole2<t2.hole2_par AND t1.hole2>t2.hole2_par-2
OR t1.hole3<t2.hole3_par AND t1.hole3>t2.hole3_par-2
OR t1.hole4<t2.hole4_par AND t1.hole4>t2.hole4_par-2
OR t1.hole5<t2.hole5_par AND t1.hole5>t2.hole5_par-2
OR t1.hole6<t2.hole6_par AND t1.hole6>t2.hole6_par-2
OR t1.hole7<t2.hole7_par AND t1.hole7>t2.hole7_par-2
OR t1.hole8<t2.hole8_par AND t1.hole8>t2.hole8_par-2
OR t1.hole9<t2.hole9_par AND t1.hole9>t2.hole9_par-2
OR t1.hole10<t2.hole10_par AND t1.hole10>t2.hole10_par-2
OR t1.hole11<t2.hole11_par AND t1.hole11>t2.hole11_par-2
OR t1.hole12<t2.hole12_par AND t1.hole12>t2.hole12_par-2
OR t1.hole13<t2.hole13_par AND t1.hole13>t2.hole13_par-2
OR t1.hole14<t2.hole14_par AND t1.hole14>t2.hole14_par-2
OR t1.hole15<t2.hole15_par AND t1.hole15>t2.hole15_par-2
OR t1.hole16<t2.hole16_par AND t1.hole16>t2.hole16_par-2
OR t1.hole17<t2.hole17_par AND t1.hole17>t2.hole17_par-2
OR t1.hole18<t2.hole18_par AND t1.hole18>t2.hole18_par-2
GROUP BY t1.player_id ORDER BY count(t1.player_id) DESC";
$result_p321 = mysql_query($query_p321);
$number = 1;
while ($row_p321 = mysql_fetch_array($result_p321)) {
$player_id2 = $row_p321["player_id"];
}
and so on..
You'll notice the "-2" in there. That is taking the par minus 2, as I don't want to record if the person is 2 strokes under. Just one stroke under. Any help is appreciated. Thank you.
Oh, also, GROUP BY needs to be used as I don't want to list the player name more than once. Just want it to count all the birdies. I guess my big problem is its not counting more than 1 per row. Thanks.
The problem is the where clause. You need to do the comparisons in the select clause in order to count them:
SELECT t1.*,
sum((t1.hole1 = t2.hole1_par - 1) +
(t1.hole2 = t2.hole2_par - 1) +
. . .
(t1.hole18 = t2.hole18_par - 1)
) as birdies
FROM scorecards t1 LEFT JOIN
courses t2 ON t1.course_id=t2.course_id
GROUP BY t1.player_id
ORDER BY birdies DESC
This uses the MySQL convention that true is 1 and false 0 to add the numbers up. An alternative formulation using standard SQL is:
sum((case when t1.hole1 = t2.hole1_par - 1) then 1 else 0 end) +
Try something like that:
SELECT t1.*, SUM( IF(t1.hole1 = t2.hole1_par-1,1,0) +
IF(t1.hole2 = t2.hole2_par-1,1,0) +
IF(t1.hole3 = t2.hole3_par-1,1,0) +
IF(t1.hole4 = t2.hole4_par-1,1,0) +
-- etc.
IF(t1.hole18 = t2.hole18_par-1,1,0) ) AS birdies
FROM scorecards t1
LEFT JOIN courses t2 ON t1.course_id=t2.course_id
GROUP BY t1.player_id
ORDER BY birdies DESC
I have two database tables containing similar data - one is the amount of work completed by a process, the other is the amount of errors made by that process.
I would like to display the percentage of right first time work.
My query for counting the number of items by process is:
SELECT Counter.Process, count( Counter.Process ) AS count
FROM Counter WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Counter.Process
ORDER BY count DESC
The above gives me a list similar to:
Process | count
-------------------
Process A | 40
Process B | 32
Process C | 102
Process D | 23
I have a second table with the same fields in it for recording errors, called 'Errors'.
By using the same query (but changing the table names obviously) I can get a list of processes and errors.
What I want to do is create a PHP web page showing the percentage of errors per process.
My problem is if I create the two queries separately, when I loop through them using a PHP Where loop I don't know how to make the calculation to show the percentage.
I tried using a UNION between the two SQL queries, but I can't get it to show the two different count readings against the process.
Ideally, I'd like a way to show the data like this:
Process | Counter.count | Errors.count
Process A 40 2
Process B 32 0
Process C 102 18
Process D 23 8
I would really appreciate any advice/suggestions as to how I can accomplish this - if you need more info on my database tables, please let me know
Thanks for reading
S
I did not run it so there might be mistakes. you can make the two selects, and left join the results:
select s.process, s.success_count, e.error_count
from
(SELECT Counter.Process as process, count( Counter.Process ) AS success_count
FROM Counter
WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Counter.Process
) s left join
(SELECT Errors.Process, count( Errors.Process ) AS error_count
FROM Errors
WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Errors.Process
) e
on (s.Process = e.process)
I personally prefer to run situations like this through PHP as it confuses me less, so I will explain how I think I would do it in PHP (I say 'think' because I might not know something about your database structure or system specifications that would make me thing otherwise):
$rows = array();
$res = mysql_query('SELECT Counter.Process, count( Counter.Process ) AS count
FROM Counter WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Counter.Process
ORDER BY count DESC');
while ($arr = mysql_fetch_assoc($res))
{
$rows[] = $arr;
}
$res2 = mysql_query('SELECT Errors.Process, count( Errors.Process ) AS count
FROM Counter WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Errors.Process
ORDER BY count DESC');
while ($arr2 = mysql_fetch_assoc($res2)
{
for ($i=0; $i<count($rows); $i++)
{
if ($arr2["Process"] == $data[$i]["process"])
{
break;
}
//Do your functions with $arr and $data[$i] at this point...
}
}
Doing it without a subquery should be simple:
SELECT
Counter.Process
, COUNT(Counter.Process) AS ProcessCount
, COUNT(Errors.Process) AS ProcessErrors
FROM
Counter
LEFT JOIN
Errors
ON Counter.Process = Errors.Process
WHERE
Counter.TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59'
GROUP BY
Counter.Process
You can do an explain on both queries to see which is the best for your data.
-edit: I've changed it to a LEFT JOIN so you don't miss rows if a process has no errors.
You could use a sub-query:
SELECT Counter.Process, count( Counter.Process ) AS Count,
(SELECT count(Errors.Process)
FROM Errors
WHERE Process=Counter.Process
AND (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')) AS Errors
FROM Counter WHERE (TIME BETWEEN '2012-07-01 00:00:00' AND '2012-07-06 23:59:59')
GROUP BY Counter.Process
ORDER BY count DESC
Regards,
Neil.
I want to count payment within selected date, but i can't figure it out how to do it.
Here is the example data from the my table
id starts_from payment_per_day
=======================================
1 2012-01-01 10,000.00
2 2012-01-15 10,500.00
3 2012-02-01 11,000.00
4 2012-02-15 11,500.00
5 2012-03-01 12,000.00
How do i count total payment from 2012-01-21 to 2012-02-20 ?
The total payment should be 338,500
from 2012-01-21 to 2012-01-31 = 11 days * 10,500
from 2012-02-01 to 2012-02-14 = 14 days * 11,000
from 2012-02-15 to 2012-02-20 = 6 days * 11,500
But if i do :
SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20'
the result is only 22,500
Any ideas ?
SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20';
I would first expand the range into the list of dates, then use the following query:
SELECT SUM(p1.payment_per_day)
FROM dates d
INNER JOIN payments p1 ON p1.starts_from <= d.date
LEFT JOIN payments p2 ON p2.starts_from <= d.date
AND p2.starts_from > p1.starts_from
WHERE p2.id IS NULL
You could obtain the list from the range with the help of a numbers table, like this:
SELECT DATE_ADD(#date_from, INTERVAL num DAY)
FROM numbers
WHERE num BETWEEN 0 AND DATEDIFF(#date_to, #date_from)
A numbers table is a thing worth having as it can be useful in many situations, so consider providing yourself with one. Here's a very simple script to create and initialise a numbers table:
CREATE TABLE numbers AS SELECT 0 AS num;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
… /* repeat as necessary, each line doubles the number of rows in the table */
But, of course, you can use a loop instead.
Here's my complete testing environment on SQL Fiddle (for anyone to play with).
It seems that it is almost impossible to do query like that, counting total each day payment within selected date.
So i work around by selecting data from all starts_from dates until <= 2012-02-20 and then picking last starts_from date which is less than 2012-01-21 (that is 2012-01-15) in order to get payment_per_day 10,500.00
Thank you for viewing my question :)