mysql date range issue with values equal to 0 within dates period - mysql

please help me with this issue:
I have the following query:
select SUM(price) from prices_adverts
where advert_id="15"
and room_type_id="3"
and (date >= "2013-09-20" AND date <"2013-09-23")
order by price
This searches to find and SUM price for the room for dates between "2013-09-20" AND "2013-09-23"
but for example if dates 2013-09-21 and 2013-09-22 have value 0 and 2013-09-20 has value 25.00 the query will return sum of 25.00 for the whole date range. When the specific date has value 0 this means the room is not available, but when even 1 day has value greater than 0 the query accept the room as available because it has total value greater than 0.. Please advise me how to change the query so if even 1 day within daterange to has value 0 the query to return total value 0 for the whole period.. I hope you to understand the nature of this issue, thanks

Try this:
IF(SUM(price = 0), 0, SUM(price))
And I assume you'd like to GROUP BY room_id.
Also I'd suggest changing those 0's in your database to NULLs. Because at some point you can possibly have 0 price, which is not equivalent to not available. You won't be able to distinguish them which is no good.

I guess you've missed GROUP BY Room_id. So it should be something like:
select room_id,
CASE WHEN MIN(price) = 0 THEN 0 ELSE SUM(price) END as priceSum
from prices_adverts
where advert_id="15"
and room_type_id="3"
and (date >= "2013-09-20" AND date <"2013-09-23")
GROUP BY room_id
ORDER BY priceSum

Related

Subquery returns more than 1 row in like %..%

i am working with bank transaction table witch contain 67000 transactions for around 800 customer from January to October so what i want is to calculate number of transactions for each customer per month i want the final result will be like cust_id , number of transaction for jan ,number of transaction for Feb ... til October i tryed this query
SELECT
cut_id,
CASE WHEN tra_date LIKE '%Oct%'
THEN
(select count(tra_date) from tab where tra_date like '%Oct%' GROUP by cut_id)
ELSE 0
END AS oct,
CASE WHEN tra_date LIKE '%Sep%'
THEN
(select count(tra_date) from tab where tra_date like '%Sep%' GROUP by cut_id)
ELSE 0
END AS sept
FROM tab
GROUP by cut_id
but i found this error #1242 - Subquery returns more than 1 row
I'm going to assume you have a sane schema that uses actual an actual datetime type for your transaction dates, rather than the apparent insane schema in the question that uses strings. Given that, your query would look like this:
SELECT
cut_id,
SUM(CASE WHEN month(tra_date) = 10 THEN 1 ELSE 0 END) AS Oct,
SUM(CASE WHEN month(tra_date) = 9 THEN 1 ELSE 0 END) AS Sept
FROM tab
GROUP by cut_id
In this section
(select count(tra_date) from tab where tra_date like '%Oct%' GROUP by cut_id)
When you do a count with a group by, and there are multiple values for the thing you are grouping by, you get multiple values. Based on your requirements, you need to choose which single value you want.
Maybe you need to do this instead
(select count(tra_date) from tab t1 where t1.tra_date like '%Oct%' and t1.cut_id = tab.cut_id)

ORDER BY datetime depending on the day AND time

I have a database field of type datetime.
The name of this field is "recallDate"
I would like to order the results in the following way:
The results must be chronological in the time: from newest to oldest
The results must be grouped by date: in other words, result having the same date are together, grouped
For every day, the results must be chronological according to the hour: earliest to latest
The results having no hour ( 00:00:00 ) have to be at the end of the results of the day
This is my actual query :
SELECT a.recallDate, a.id, a.id_company, com.name, a.recallType
FROM PDT_CRM.actions a
INNER JOIN PDT_CRM.traders as trad on trad.id=a.id_traders
WHERE DATE(a.recallDate) > DATE(NOW() + INTERVAL 30 DAY)
ORDER BY TIME(a.recallDate) , a.recallType
It is very likely that I have to use CASE but I don't understand how to use it.
You can use the following code to create a specific order that will put times '00:00:00' at the very end of the day:
...
ORDER BY date(a.rappelDate),
case when time(a.rappelDate) = 0 then 1 else 0 end,
time(a.rappelDate)

How do I get the max date and stage name for a certain value?

I am working on a query to pull the max date that is greater than a given period of time and have it return the value that is in that date.
I'm working from a salesforce table and want to pull the max date that an opportunity is in and return the stage name that it is in. The date has to be greater than 5-1-14. So do I have to break this up into multiple queries? Give me the max date then return the stage name that its in. Any help would be appreciated!! Thanks!
SELECT OpportunityID,
Max(case when CREATEDDATE < '2014-05-01' THEN STAGENAME END) as Q1_FY15_Stage
FROM [BVSFWarehouse].[dbo].[sf_OPPORTUNITYHISTORY]
GROUP by OPPORTUNITYID
You can filter your SELECT statement with a WHERE clause to limit the dates. Try:
SELECT
OpportunityID
,STAGENAME
,MAX(CREATEDATE)
FROM BVSWarehouse.dbo.sf_OPPORTUNITYHISTORY
WHERE
CREATEDATE > '2015-05-01'
GROUP BY
OpportunityID
,STAGENAME

Mysql returns null for rows that doesn't exist

I have the following code:
while ($row = mysql_fetch_array($result)){
$que ='select SUM(price) from prices_adverts where advert_id="7" and room_type_id="54" and (date >= "2013-09-20" AND date <"2013-09-21") order by price';
$que ='select SUM(price) from prices_adverts where advert_id="7" and room_type_id="55" and (date >= "2013-09-20" AND date <"2013-09-21") order by price'; and etc
$res=mysql_query($que) or die();
$rw=mysql_fetch_row($res);
$price= $rw['0'];
}
this returns sum for some records that have prices in the database and NULL for $price for the records dont exist /when a room doesnt has price for specific dates it doesn't exist in the table /
So my question is how I can get result for records that exist only??? I do not need NULL values for prices and is it possible to access $price outside while ? How? Please help, thanks
May I explain what exactly I need, this may help you to help Me :)
Above I am looping hotels rooms to check how much would cost the room for specific period. Than I need to draw button outside loop which will divert visitor to reservation page. But if a hotel has no room prices available for the dates, I wish to have no button for reservation. That's why I need to figure out is there at least 1 room with prices in the hotel or not.. Hope this helps
########################################################Update
first query: I am taking all London hotels id-s
select id from adverts where town="London" limit 0, 5
than
for($i=0;$i<$num_rows;$i++){
$row=mysql_fetch_row($result);
echo echo_multy_htl_results($row[0]);
}
this function echo_multy_htl_results is:
select a.article_title, a.town, a.small_image, a.plain_text, a.star_rating, a.numberrooms, rta.room_type_id, rt.bg_room_type,a.longitude, a.latitude, a.link_name, a.id from adverts a, rooms_to_adverts rta,room_types rt where a.id = rta.advert_id and rta.advert_id="3" and rta.room_type_id=rt.id and rt.occupants>="1" group by rt.bg_room_type order by rt.occupants ASC
it gets info for the html hotel square and also room_types_id-s and that it comes the cod already added.. What would you suggest ?
Maybe by adding AND price IS NOT NULL ?
The solution to the immediate problem at hand can be this query:
select SUM(price)
from prices_adverts
where advert_id="7"
and room_type_id="54" -- notice, we are filtering on room type here
and (date >= "2013-09-20" AND date <"2013-09-21")
group by room_type_id -- this makes no rows appear when there are no rows found in this case
order by price
It returns 1 row, when there were a corresponding rows, and 0 rows, when there were none.
However, your problem seems to be of a different nature. Your scheme of operation seems to be like this:
query rows from the DB (room_type_ids)
put them in a loop
for each iteration run a query
This is bad. Databases are very good at solving these kinds of problems, using JOINs, and the other appropriate clauses. I'd suggest using these features, and turning things around in your head. That way, you could issue one query returning all data you need. I believe this might be such a query, providing all the room type IDs with their summed prices:
select room_type_id, SUM(price)
from prices_adverts
where advert_id="7" -- notice: no filtering for room_type_id this time
and (date >= "2013-09-20" AND date <"2013-09-21")
group by room_type_id
order by price
This query lists all room_type_ids that have records, and does not list those that don't, and beside each different type_id, it has the summed price. You can see the results in this SQL fiddle. (the data types are obviously off, this is just to show it in operation)
EDIT
To have the advert IDs similar to the room_type_ids too:
select advert_id, room_type_id, SUM(price)
from prices_adverts
where (date >= "2013-09-20" AND date <"2013-09-21")
-- notice: no filtering for room_type_id or advert id this time
group by advert_id, room_type_id
order by price
This will have three columns: advert_id, room_type_id and the summed price...
You could use
sum(case when price is null then 0 else price end)
or
sum(isnull(price,0))
or
just add in your where clause `price is not null` to exclude them.
You need to use HAVING
select SUM(price)
from prices_adverts
where advert_id="7" and room_type_id="54" and (date >= "2013-09-20" AND date <"2013-09-21")
having sum(price) is not null
order by sum(price)

mysql get avg value on a a field that needs to be modified first based on results of a case statement

I am attempting to get the weekly average of a field "weight" over a specified date range using mySQL. The spanner in the works here is that the weight is stored in Kg in some records and lbs in others. There is also a flag in the table (unitsMode) that specifies whether the weight is a metric or imperial one. So I need to perform a calculation on the weight field based upon the unitsMode - am doing this using CASE. But now I can't do the average, or rather do not know "where" to do the average. Am doing this as a stored procedure, current code below:
PROCEDURE `weeklyweighttest`(IN uId INTEGER, IN rangeStart DATE, IN rangeEnd DATE)
BEGIN
select weight,unitsMode, floor(DATEDIFF(entryDate,curdate())/7) as weeks_ago, CASE unitsMode
WHEN 1 THEN truncate((weight/2.2),2)
WHEN 0 THEN truncate(weight,2)
END AS calcWeight
FROM `mydatabasetable` WHERE userId=uId AND entryDate >= rangeStart AND entryDate <= rangeEnd
GROUP BY floor(DATEDIFF(entryDate,curdate())/7);
END
Many thanks in advance for any input here
Try putting the AVG around the case statement:
AVG(CASE unitsMode
WHEN 1 THEN truncate((weight/2.2),2)
WHEN 0 THEN truncate(weight,2)
END) AS calcWeight