MySQL select between two dates not working as expected - php

I'm trying to create a query that will select all dates between two dates
This is my query:
$query = "SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '$date1' AND '$date2' AND D1.D1_ID = D2.D2_ID";
The trouble is, it is not returning anything, but not producing an error either
So I tried inputting it directly into phpMyAdmin like this
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
AND D1.D1_ID = D2.D2_ID`
then like this
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
and like this
SELECT * FROM D1
WHERE DATE_ADDED BETWEEN '2011-01-01' AND '2011-12-12'
and I just get
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0003 sec )
Yes, my tables exist, and so do the columns :)

In the first cases the lack of results could be because of the inner join. For a result to be in the set it would require a record in both tables, ie. a record from d1 would not appear unless d2 also had that id in the d2_id column. To resolve this, if that is correct for your business logic, use left join.
However, the last of your cases (without the join) suggests the reasons is a lack of matching records in the first (left) table d1.
Without the full dataset we can't really comment further, since all the code you are running is perfectly valid.

If you always want to select an entire year it is easer to select it like this:
SELECT * FROM D1 WHERE YEAR(DATE_ADDED) = 2011;

Please implement below code
SELECT DISTINCT * FROM D1,D2
WHERE D1.DATE_ADDED BETWEEN DATE_FORMAT('2011-01-01','%Y-%m-%d')
AND DATE_FORMAT('2011-12-12','%Y-%m-%d')
AND D1.D1_ID = D2.D2_ID`

Related

Duplicate records in MySQL. EXISTS check for the same data not working properly?

SELECT EXISTS
(SELECT * FROM table WHERE deleted_at IS NULL and the_date = '$the_date' AND company_name = '$company_name' AND purchase_country = '$p_country' AND lot = '$lot_no') AS numofrecords")
What is wrong with this mysql query?
It is still allowing duplicates inserts (1 out of 1000 records). Around 100 users making entries, so the traffic is not that big, I assume. I do not have access to the database metrics, so I can not be sure.
The EXISTS condition is use in a WHERE clause. In your case, the first select doesn't specify the table and the condition.
One example:
SELECT *
FROM customers
WHERE EXISTS (SELECT *
FROM order_details
WHERE customers.customer_id = order_details.customer_id);
Try to put your statement like this, and if it returns the data duplicated, just use a DISTINCT. (SELECT DISCTINCT * .....)
Another approach for you :
INSERT INTO your_table VALUES (SELECT * FROM table GROUP BY your_column_want_to_dupplicate);
The answer from #Nick gave the clues to solve the issue. Separated EXIST check and INSERT was not the best way. Two users were actually able to do INSERT, if one got 0. A single statement query with INSERT ... ON DUPLICATE KEY UPDATE... was the way to go.

Duration between type in and out in MYSQL

I am new MYSQL now i try something here is my query not accurate result
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time))) FROM `officialbreaks` where type='out'
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time))) FROM `officialbreaks` where type='in'
Any buddy have work on that type of situation.
OUT REQUIRED
TIMEDIFF(time where type=in, time where type=out)
3:35:30 time type=in, 03:35:30 time type=out
Output 0
You can try as per below-
SELECT DISTINCT a.userid, (TIME_TO_SEC(b.time) - TIME_TO_SEC(a.time)) AS 'time_diffrence' FROM
(SELECT userid,`time` FROM mytable WHERE `type`='in') a
JOIN (SELECT userid,`time` FROM mytable WHERE `type`='out') b ON a.userid=b.userid
It is a simple solution but there can be multiple out time against single in time and multile users etc. so there can be so many combination where query need to change.

How to improve Mysql database performance without changing the db structure

I have a database that is already in use and I have to improve the performance of the system that's using this database.
There are 2 major queries running about 1000 times in a loop and this queries have inner joins to 3 other tables each. This in turn is making the system very slow.
I tried actually to remove the query from the loop and fetch all the data only once and process it in PHP. But this is putting to much load on the memory (RAM) and the system is hanging if 2 or more clients try to use the system.
There is a lot of data in the tables even after removing the expired data .
I have attached the query below.
Can anyone help me with this issue ?
select * from inventory
where (region_id = 38 or region_id = -1)
and (tour_opp_id = 410 or tour_opp_id = -1)
and room_plan_id = 141 and meal_plan_id = 1 and bed_type_id = 1 and hotel_id = 1059
and FIND_IN_SET(supplier_code, 'QOA,QTE,QM,TEST,TEST1,MQE1,MQE3,PERR,QKT')
and ( ('2014-11-14' between from_date and to_date) )
order by hotel_id desc ,supplier_code desc, region_id desc,tour_opp_id desc,inventory.inventory_id desc
SELECT * ,pinfo.fri as pi_day_fri,pinfoadd.fri as pa_day_fri,pinfochld.fri as pc_day_fri
FROM `profit_markup`
inner join profit_markup_info as pinfo on pinfo.profit_id = profit_markup.profit_markup_id
inner join profit_markup_add_info as pinfoadd on pinfoadd.profit_id = profit_markup.profit_markup_id
inner join profit_markup_child_info as pinfochld on pinfochld.profit_id = profit_markup.profit_markup_id
where profit_markup.hotel_id = 1059 and (`booking_channel` = 1 or `booking_channel` = 2)
and (`rate_region` = -1 or `rate_region` = 128)
and ( ( period_from <= '2014-11-14' and period_to >= '2014-11-14' ) )
ORDER BY profit_markup.hotel_id DESC,supplier_code desc, rate_region desc,operators_list desc, profit_markup_id DESC
Since we have not seen your SHOW CREATE TABLES; and EXPLAIN EXTENDED plan it is hard to give you 1 answer
But generally speaking in regard to your query "BTW I re-wrote below"
SELECT
hotel_id, supplier_code, region_id, tour_opp_id, inventory_id
FROM
inventory
WHERE
region_id IN (38, -1)
AND tour_opp_id IN (410, -1)
AND room_plan_id IN (141, 1)
AND bed_type_id IN (1, 1059)
AND supplier_code IN ('QOA', 'QTE', 'QM', 'TEST', 'TEST1', 'MQE1', 'MQE3', 'PERR', 'QKT')
AND ('2014-11-14' BETWEEN from_date AND to_date )
ORDER BY
hotel_id DESC, supplier_code DESC, region_id DESC, tour_opp_id DESC, inventory_id DESC
Do not use * to get all the columns. You should list the column that you really need. Using * is just a lazy way of writing a query. limiting the columns will limit the data size that is being selected.
How often is the records in the inventory are being updates/inserted/delete? If not too often then you can use consider using SQL_CACHE. However, caching a query will cause you problems if you use it and the inventory table is updated very often. In addition, to use query cache you must check the value of query_cache_type on your server. SHOW GLOBAL VARIABLES LIKE 'query_cache_type';. If this is set to "0" then the cache feature is disabled and SQL_CACHE will be ignored. If it is set to 1 then the server will cache all queries unless you tell it not too using NO_SQL_CACHE. If the option is set to 2 then MySQL will cache the query only where SQL_CACHE clause is used. here is documentation about query_cache_type
If you have an index on those following column in this order it will help you (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id)
ALTER TABLE inventory
ADD INDEX (hotel_id, supplier_code, region_id, tour_opp_id, inventory_id);
If possible increase sort_buffer_size on your server as most likely you issue here is that your are doing too much sorting.
As for the second query "BTW I re-wrote below"
SELECT
*, pinfo.fri as pi_day_fri,
pinfoadd.fri as pa_day_fri,
pinfochld.fri as pc_day_fri
FROM
profit_markup
INNER JOIN
profit_markup_info AS pinfo ON pinfo.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_add_info AS pinfoadd ON pinfoadd.profit_id = profit_markup.profit_markup_id
INNER JOIN
profit_markup_child_info AS pinfochld ON pinfochld.profit_id = profit_markup.profit_markup_id
WHERE
profit_markup.hotel_id = 1059
AND booking_channel IN (1, 2)
AND rate_region IN (-1, 128)
AND period_from <= '2014-11-14'
AND period_to >= '2014-11-14'
ORDER BY
profit_markup.hotel_id DESC, supplier_code DESC, rate_region DESC,
operators_list DESC, profit_markup_id DESC
Again eliminate the use of * from your query
Make sure that the following columns have the same type/collation and same size. pinfo.profit_id, profit_markup.profit_markup_id, pinfoadd.profit_id, pinfochld.profit_id and each one have to have an index on every table. If the columns have different types then MySQL will have to convert the data every time to join the records. Even if you have index it will be slower. Also, if those column are characters type (ie. VARCHAR()) make sure they are of the CHAR() with a collation of latin1_general_ci as this will be faster for finding ID, but if you are using INT() even better.
Use the 3rd and 4th trick I listed for the previous query
Try using STRAIGHT_JOIN "you must know what your doing here or it will bite you!" Here is a good thread about this When to use STRAIGHT_JOIN with MySQL
I hope this helps.
For the first query, I am not sure if you can do much (assuming you have already indexed the fields you are ordering by) apart from replacing the * with column names (Don't expect this to increase the performance drastically).
For the second query, before you go through the loop and put in selection arguments, you could create a view with all the tables joined and ordered then make a prepared statement to select from the view and bind arguments in the loop.
Also, if your php server and the database server are in two different places, it is better if you did the selection through a stored procedure in the database.
(If nothing works out, then memcache is the way to go... Although I have personally never done this)
Here you have increase query performance not an database performance.
For both queries first check index is available on WHERE and ON(Join) clause columns, if index is missing then you have to add index to improve query performance.
Check explain plane before create index.
If possible show me the explain plane of both query that will help us.

Running a query on query result? (PHP + SQL)

I currently have a table with 1,100,000 rows which contains user's data.
Its format is sort of like this:
User_Id Date Action
I was wondering, instead of searching each time on the whole table for the actions that were made by a specific user on a specific date by doing the following:
SELECT Action FROM USERS_TABLE WHERE Date=08092014 AND User_Id=5
SELECT Action FROM USERS_TABLE WHERE Date=09092014 AND User_Id=5
SELECT Date FROM USERS_TABLE WHERE Action="Shopping" AND User_Id=5
SELECT Date FROM USERS_TABLE WHERE Action="Eating" AND User_Id=5
etc.
Maybe I could do something like that:
SELECT * FROM USERS_TABLE WHERE User_Id=5
And on top of this query's results I could run the above queries, which I think will result a faster execution time (correct me if I'm wrong)
Do you guys know how to do that?
You could combine all of those queries into one query using an or.
SELECT *
FROM USERS_TABLE
WHERE (Date = 09092014 OR Date = 08092014)
AND (Action="Shopping" OR Action="Eating")
AND User_Id = 5
I assume you have a table with unique users ids. if you don't, you might consider it? How can a profile be managed if there is no single entry for a single user? anyway that's not my business, but let's just assume you have such a table, with a unique field with the User_Id
it's named USERS here
SELECT Action,Date
FROM USERS
LEFT JOIN USERS_TABLE AS Actions
ON (Actions.User_Id=USERS.User_Id AND Date IN (08092014,09092014))
LEFT JOIN USERS_TABLE AS Dates
ON (Dates.User_Id=USERS.User_Id AND Action IN ("Shopping","Eating"))
WHERE USERS.User_Id=5
be sure to index User_Id, Date And Action since we are searching on them.
I would do a crosstab query, after I indexed the User_Id column -
SELECT `Date`,
SUM(IF(`Action` = 'Eating', 1, 0)) AS `Eating`,
SUM(IF(`Action` = 'Shopping', 1, 0)) AS `Shopping`
FROM `USERS_TABLE`
WHERE `User_Id` = 5
GROUP BY `Date`
You'll get a result like this -
+-------------+---------------+----------+
Date Eating Shopping
+-------------+---------------+----------+
2002-03-01 59 72
2002-03-02 28 0
2002-03-03 22 17
2002-03-04 36 13
2002-03-06 12 0
+-------------+---------------+----------+
For expediency I might store this data in a temp table (with a user id column). This can be modified to accept date ranges and other limitations. That gives me some additional flexibility down the line when I need to aggregate date from multiple users.
I think what you mean is answered by this:
select action, actiondate
from
(select *
from USERS_TABLE
where user_id = 5) as filter
Fiddle here.
The derived table basically acts as the filter you describe.
Whether it would be any faster is hard to predict - I'd run it on your production system, and see what the query plan says.

MySQL - selecting from multiple tables, possibly without joins?

It's been a while since I needed help, but today I'm here to basically get assistance from your knowledge. I'm currently quite stuck on a very annoying SQL problem, which is the following.
I have two tables. Painteditems, and specialitems. Both tables have unique column names (painteditemid, specialitemid etc), yet both tables share similar values. I want to get results from both tables.
Let's say this is my setup:
PaintedItems
paintedItemName
paintedItemColor
visible
SpecialItems
specialItemName
specialItemColor
visible
I used this query:
SELECT *
FROM `painteditems` AS pa,
`specialitems` AS sp
WHERE (pa.`visible` = 1
OR sp.`visible` = 1)
AND (pa.`painteditemname` = 'itemname1'
OR sp.`specialitemname` = 'itemname1')
AND (pa.`painteditemcolor` = 'black'
OR sp.`specialitemcolor` = 'black')
That resulted in:
Showing rows 0 - 29 ( 259,040 total, Query took 39.4352 sec)
even though both tables contain only 10.000 rows altogether. Adding this did nothing:
GROUP BY pa.`painteditemid`, sp.`specialitemid`
Still 260k rows. How should I approach this?
Thank you in advance.
edit: fixed spacing, code blocks
Sure sounds like you want a UNION between the two tables. Right now, you are getting a cartesian product which is why the results are so large:
select *, 'painted' Source
from painteditems
where visible = 1
and painteditemname = 'itemname1'
and painteditemcolor = 'black'
union all
select *, 'special' Source
from specialitems
where visible = 1
and specialitemname = 'itemname1'
and specialitemcolor = 'black'
You will need to replace the SELECT * with your column names. Also the number of columns and datatypes must match in both queries.
UNION ALL will return all rows from both tables, if you only want DISTINCT rows then you will want to use UNION
The UNION operator is used to combine the result-set of two or more SELECT statements. Defiantly You can make use of UNION as shown in the #bluefeet's answer If you meet below conditions.
SELECT statement within the UNION must have the same number of
columns
The columns must also have similar data type
The columns in each SELECT statement must be in the same order.
I would do this with a union all in the subquery:
select *
from ((select paintedItemName as ItemName, paintedItemColor as ItemColor, visible, 'Painted' as which
from painteditems
) union all
(select specialItemName, SpecialItemColor, visible, 'Special' as which
from specialitems
)
) t
where visible = 1 and itemname = 'itemname1' and itemcolor = 'black'
This allows you to have only one set of results. In a union, the column names come from the first subquery, which this renames to more generic names. The reason I prefer this approach is because the where clause does not need to be repeated multiple times -- which can lead to errors and maintenance problems.

Categories