SQL Left Join - Multiple Rows in Right Table - php

I am trying to make PHP / MySQL Search Form. When a user wants to search he need to fill 3 input fields: FromDate, ToDate and SucategoryID.
There are 2 tables: Items and ItemsBlockDates
In Table Items, there is info about the item and it is identified by ID.
In Table ItemBlockDates, there is info about a period when Item will not be displayed in search results. It contains: ItemID, FromDate, and Date fields. Also, there is a possibility to define more than one Block Date for one item.
Now, I want to select all Items where FromDate and To Date inputs does not match with any of rows in ItemsBlockDates with same ItemID.
I wrote a query, but there is a problem:
SELECT *
FROM Items
LEFT JOIN ItemBlockDates ON Items.ID = ItemBlockDates.ItemID
WHERE Items.SubcategoryID = :SubcategoryID
AND ItemBlockDates.FromDate NOT BETWEEN CAST(:FromDate AS DATETIME) AND CAST(:ToDate AS DATETIME)
When I run this query it does not display Items where Block Dates are not set, also it displays items where more than one Block Date is set.

I want to select all Items where FromDate and To Date inputs does not
match with any of rows in ItemsBlockDates with same ItemID.
To me, this suggests NOT EXISTS:
SELECT i.*
FROM Items i
WHERE i.SubcategoryID = :SubcategoryID AND
NOT EXISTS (SELECT 1
FROM ItemBlockDates ibd
WHERE i.ID = ibd.ItemID AND
ibd.FromDate BETWEEN CAST(:FromDate AS DATETIME) AND CAST(:ToDate AS DATETIME)
);
If you are passing in a parameter, I'm not sure why you need to convert to a DATETIME. You should be able to pass it in with the correct type.

Related

Pulling data from MySQL database and pulling only 1 value of each in a column and then show latest first

What I'm trying to do.
To pull data from a database. With one column 'serial_no' to only pull 1 of each value so it's unique, and any other values within the 'serial_no" column to not show if another one of the same value exists. So in column 'serial_no' there could be 35k values but it would only show 35 if there are a total of 35 unique serial numbers. Once I have them I need them to show the latest first by 'datetime' column.
Current outcome.
I have the data pulling through, and it's only showing once of each 'serial_no' however, it's not showing the latest first, like it seems to be ignoring the ordering or just pulling through the first one it sees rather than the latest.
These 2 PHP queries I have used and working but not 100% how it should. The first one, i only want 'serial_no" distinct not all columns, so maybe that's why this one is not working.
$sql = "SELECT DISTINCT serial_no, datetime FROM wp_clicker_data ORDER BY datetime DESC";
The other one which works fine apart from it does not show the latest value of a specific serial_no
$sql = "SELECT * FROM wp_clicker_data GROUP BY serial_no ORDER BY datetime DESC";
Any ideas how each unique value of column 'serial_no' can pull through the latest entry based on the latest 'datetime' column?
Thanks!
Use Max and GROUP BY to get your desired output as below-
SELECT serial_no,
MAX(datetime)
FROM wp_clicker_data
GROUP BY serial_no
If you want the latest row for each serial number, then use filtering:
select cd.*
from wp_clicker_data cd
where cd.datetime = (SELECT MAX(cd2.datetime)
FROM wp_clicker_data cd2
WHERE cd2.serial_no = cd.serial_no
);
GROUP BY is not appropriate when you want to retrieve entire rows. Using SELECT * with GROUP BY doesn't make sense, because there are columns in the SELECT that are not in the GROUP BY. And this construct generally won't work (with the default settings) in the more recent versions of MySQL.

SELECT DISTINCT count entries within each month. MYSQL

Hi I have a database with a column containing email addresses and a second column containing category and a third column containing date.
What I want to do is count the number of unique email addresses in category 'A' between multiple date ranges. So I have this:
SELECT COUNT(DISTINCT email) as counter
FROM table
WHERE category = "A" AND date < "2015-12" AND date > "2015-11";
Then I'll do a separate query for the second date range.
NOW HERE'S MY PROBLEM:
If an email address appears in month one, and also in month two it will go on the count for both months because it's unique within the range I'm querying.
How do I create a query that will count the unique email addresses for a year let's say, then count the distinct entries in a month period without including the duplicates?
Thanks!
If you want custom date you can set the value to vars
$custom_date_begin = "2015-01-10";
$custom_date_end = "2015-02-10";
then for vars and the month group by you can use somethings like this
"SELECT COUNT(DISTINCT email) as counter
FROM table
WHERE category = 'A'
AND date >= '$custom_begin_date' AND date <='$custom_end_date'
group by MONTH (date);"
Information provided is not enough for writing adequate query. So I'll try to guess details.
Lets assume that we need to count number of unique emails for each month and category.
The query could be like the following:
SELECT dt, category, COUNT(*) AS cnt
FROM (
SELECT LEFT(`date`,7) AS dt, category, email
FROM table
GROUP BY LEFT(`date`,7), category, email
) x
GROUP BY dt, category
If you have variable date ranges, then you'd better group on daily basis, and then count emails via script for each date range.

Select Data Based on Column Less Than Current Date and Empty Columns

For example, i have two tables like this
Table User:
Table Payment:
I want to join two table above, but i want to get the result as quantity,
How many of blanks price columns based from previous of current date.
So if current date is 2015-04-10, the result will be look like this:
I don't have any clue how to do that using some syntax query combination in SQL or in PHP to display the result
In SQL, you could do something like this:
SELECT user_name, COUNT(name) AS result
FROM user
JOIN payment ON users.id = payment.id_user
WHERE (price IS NULL OR ltrim(price) = '')
AND payments.last_pay < '2015-04-10'
GROUP BY payment.id_user
You can see the result of this query in the SQL Fiddle.

MySQL Query showing only the last item grouped by user

I got a database that registers user actions and their geolocation.
Now I would like to fetch this data at the hand of the last action per user.
The table looks a bit like:
geoaction_id AUTO INCREMENT
geoaction_user
geoaction_creationdate (Y-m-d H:i:s)
geoaction_action
geoaction_lon
geoaction_lat
Now I would like to make a simple query that selects of all users the last item.
But LIMIT 0,1 just parses one row no matter what. (LOGICALLY!!)
Group by gives a little better result.
But how to get only the last item per user?
Try this, please provide the queries you have checked out so far, in order to assist you better.
SELECT geoaction_user, geoaction_action
FROM table-name
GROUP BY geoaction_user
ORDER BY geoaction_action DESC LIMIT 1
Working with sets:
SELECT
g.geoaction_user,
g.geoaction_action,
g.geoaction_creationdate,
g.geoaction_lat,
g.geoaction_lon
FROM
(
SELECT
geoaction_user,
MAX(geoaction_id) max_id
FROM
geoactions
GROUP BY geoaction_user
) s
JOIN
geoactions g
ON s.geoaction_user = g.geoaction_user
AND s.max_id = geoaction_id
The subquery generates a virtual table with the geoaction_id from the latest entry in the tabble for each user_id, then the table is joined to get the data belong to the latest id.
If you need to filter out some records place the where clause in the subquery

How do I efficiently select unique row/record data from 2 mysql tables and return one merged result, ordered by timestamp?

Stack:
I'm trying to turn my website's user profile into more of a feed style page. Currently the profile shows some user stats at the top, then the last 10 comments a user submitted (ordered by timestamp descending), then the last 10 posts they have submitted.
What I want to do instead, is have the last 20 "actions" (either comment or post submission) listed in order of the timestamp (so the comments and submissions will be merged together in the list instead of having 2 seperate lists). You know, like a "feed."
The issue is that the comments are pulled from a comments table, and the submissions are pulled from a "submissions" table.
I've solved it in a pretty inefficient way by using a union query to select "comment_id/submission_id", "field the identifies record as a comment or a submission", "timestamp" from both tables.
This gives me a result that tells my the entity id, as well as defines the entity as a comment or a post, by which I can then shoot off another query in a while mysql_fetch_array statement to get the full comment or submission data.
This just seems really dirty to me, since I'm basically querying the tables, finding the rows/records that I need (but ignoring the actual data I need since the different table's columns don't match up as I believe to be necessary for a union query), then going back for the data I ignored the first time with individual queries in a while statement...
Is there a better way to do this that I don't know of?
Additional notes:
Example sql I'm currently using to build the initial result I spoke of above:
select comment_id, datatype, timestamp from comments where userid=3
union all
select content_id, datatype, timestamp from submissions where userid=3
ORDER BY timestamp DESC
Returns a result like this:
commentid datatype timestamp
5201 post 2012-03-27 20:30:40
43761 comment 2012-03-26 21:00:19
43759 comment 2012-03-26 20:59:47
5033 post 2012-03-26 20:57:36
43755 comment 2012-03-26 20:54:57
43745 comment 2012-03-26 16:32:24
Pseudocode I can then use to print out the information onto the profile page:
while ($content_array = mysql_fetch_array($abovequery)){
Individual select query fetching the full row by from either comment table or submission table by id depending on $content_array['datatype'];
echo out relevant data from individual select query onto profile screen in a pretty way;
}
Surely this can be done better?
If you are unable to coerce the columns of the two full queries in such a way that it can all be returned in the UNION then you could join the union result to the comments and submissions tables.
SELECT records.datatype, comments.*, submissions.*
FROM (
(
SELECT comment_id, datatype
FROM comments
WHERE userid=3
ORDER BY timestamp DESC
LIMIT 20
) UNION ALL (
SELECT content_id, datatype
FROM submissions
WHERE userid=3
ORDER BY timestamp DESC
LIMIT 20
)
ORDER BY timestamp DESC
LIMIT 20
) AS records
LEFT JOIN comments
ON records.comment_id = comments.comment_id
AND records.datatype = 'comment'
LEFT JOIN submissions
ON records.comment_id = submissions.content_id
AND records.datatype = 'post'
Alternatively, you could run the two innermost selects with all required fields and then order the final result in PHP.

Categories