How to select rows from MySQL table with max values - php

I have a table with multiple rows for each customer and and a visit_date. The visit date can be null as well.
My tables are as below:
customers:
id | name | email
1 | John Doe1 | a.b#gmail.com
2 | John Doe2 | b.c#gmail.com
3 | John Doe3 | x.y#gmail.com
store_customers
id | customer_id | store_id | email_optedin | visit_date
1 | 1 | 1 | 1 | 2015-11-30
2 | 1 | 2 | 1 | 2016-05-08
3 | 1 | 3 | 1 | null
4 | 2 | 1 | 1 | 2015-04-30
5 | 2 | 2 | 1 | 2015-08-40
6 | 2 | 3 | 1 | 2015-12-12
7 | 3 | 1 | 1 | null
8 | 3 | 2 | 1 | null
9 | 3 | 3 | 1 | null
I am trying to retrieve customers who either have not had a visit to the any of the three stores or have not visited since a specified date (e.g. 2016-04-15).
I am expecting customers 2 and 3 but not 1.
I tried this query:
select distinct * from customers
inner join store_customers on store_customers.customer_id = customers.id
where customers.email != '' and
store_customer.store_id in (1,2,3) and customers.emailStatus not in ('Unverified','Bounced','Spammed')
and
(
store_customer.email_optedin = 1
and max(store_customers.visit_date) <= '2016-04-15'
or account_customer.visit_date is null
);
This does not work. I somehow need to, for the set of store ids), I need to select customers who have either not had any visit (all nulls for visit date for the specified stores) or the if one or more visit dates are available then compare the max date to the specified date.
I found similar questions but none of the answers has worked for me, mainly because of the requirement of selecting either those customers who have no visit or if they do atleast one, then to compare the latest visit date from the set of stores in the joined table.
I am trying to do this all in one query but if that is not possible then I can break it up as well. I also do not want to change the order of joins because there are many other things added on to this query and changing the order of joins may become a problem.
I really appreciate any help that can be provided.
Regards,
Waqar

Try this query
SELECT
customers.id,
customers.name,
MAX(store_customers.visit_date)
FROM
customers LEFT JOIN store_customers on customers.id = store_customers.customer_id
GROUP BY customers.id,customers.name
HAVING MAX(store_customers.visit_date) < '2016-04-15' OR MAX(store_customers.visit_date) IS NULL

Related

How to SELECT DISTINCT one column and ORDER by another column?

I have a table like this
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
id | domain | domain_date | domain_status |
1 |abc_com | 2022-08-20 15:42:35 | 1 |
2 |def_com | 2022-08-20 15:44:31 | 1 |
3 |def_com | 2022-08-20 15:40:05 | 1 |
4 |abc_com | 2022-08-20 15:35:05 | 0 |
5 |ghi_com | 2022-08-20 15:25:05 | 1 |
6 |ghi_com | 2022-08-20 15:25:00 | 1 |
7 |abc_com | 2022-08-19 15:22:00 | 1 |
8 |ghi_com | 2022-08-20 15:25:05 | 1 |
9 |abc_com | 2022-08-20 15:21:00 | 1 |
10 |abc_com | 2022-08-19 15:21:20 | 1 |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
I want to get latest entries of five records from the table but I don't want duplicate domains.
I tried with SELECT DISTINCT, Distinct works fine if I select only domain it cuts the duplicates but if selects two columns
SELECT DISTINCT domain, domain_date FROM Domains
It still shows duplicates because the dates are different
What is the workaround for this?
if you group on max domain date, you will get a distinct list of domains with their max domain_date:
select
domain, max(domain_date) as MaxOfDomainDate
from table
group by domain
We can join the table on this result set if we want to get the status that goes with the domain record for that date:
select A.domain, A.domain_date, A.domain_status
from
table A
inner join
(
select
domain, max(domain_date) as MaxOfDomainDate
from table
group by domain
) B
on A.domain = B.domain
and A.domain_date = B.domain_date;
You should be able to add ordering and TOP or LIMIT to such a query pretty easily to get the "latest 5" and so on (I'll leave that as an exercise to the reader ;) )
I think that you may want domain_date values to be unique.
SELECT DISTINCT domain WHERE domain_date UNIQUE

Finding inner join mysql with array [duplicate]

This question already has answers here:
How to join two tables using a comma-separated-list in the join field
(5 answers)
Closed 2 years ago.
I have two tables, First one is products where it has list of products with some specifications, in the other hand I have a table with clients and what type of product they want, they might want a product in any town of a list exactly as explained in the following tables,
Products Table like
| id | owner | userid | city | town | status | price |
| 1 | jon spee | 10 | 10 | 4 | 0 | 10500 |
| 2 | Hiss Roe | 10 | 7 | 9 | 0 | 20000 |
| 3 | John Smi | 10 | 10 | 12 | 0 | 10000 |
Clients Table like
| id | fullname | userid | city | towns | status | price |
| 1 | name 1 | 10 | 10 |4,8,6,2| 0 | 20000 |
| 2 | name 2 | 10 | 7 | 7,2,9 | 0 | 25000 |
| 3 | name 3 | 10 | 10 | 1 | 0 | 20000 |
MySQL Query :
SELECT *
FROM clients
INNER JOIN products
ON (
clients.userid = products.userid AND
clients.price >= products.price AND
clients.city = products.city AND
clients.status = products.status
I want it to check also in towns like for each town it executs this query (dynamically),
(products.town LIKE '%4%' OR products.town LIKE '%8%' OR products.town LIKE '%6%' OR products.town LIKE '%2%')
You could go with this query
SELECT *
FROM clients
INNER JOIN products
ON (
clients.userid = products.userid AND
clients.price >= products.price AND
clients.city = products.city AND
find_in_set(clients.town, products.town) AND
clients.status = products.status
you can also fetch it in php and create your statement based on the results fetched
Your primary effort should go into fixing your data model. Don't store multiple integer values in a string column. You should have a separate table to store the relation betwen clients and towns, which each tuple on a separate row.
That said: for your current design, you can join on find_in_set():
on
clients.userid = products.userid
and ...
and find_in_set(product.town, client.towns)

MySQL: Link answers to comments, grouped and limited

I got the following MySQL table:
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 4 | -1 | 2 |
| 5 | 4 | 2 |
| 6 | 4 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
>| 9 | -1 | 2 |
>| 10 | -1 | 1 |
>| 11 | -1 | 2 |
+----+--------+------+
> = original comment
The entries with answer = -1 are the original comments.
The entries with answer != -1 are answers to the comment with the respective id.
Furthermore there are types of comments (in this case 1 or 2).
Now I want to retrieve the original comments (for a specified type and a specified limit) and their answers (type and limit do not matter). Further it would be great to group the result by the two types (again, only the original comment's type matters for grouping).
A query result for type=1 and limit=2 should look like that (not grouped yet):
+----+--------+------+
| id | answer | type |
+----+--------+------+
>| 1 | -1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
>| 7 | -1 | 1 |
| 8 | 7 | 2 |
+----+--------+------+
I have tried several kinds of queries for hours now, can I implement it without a procedure? What would the procedure look like?
I would appreciate your help a lot.
Use a subquery to get 2 original comments of type-1 first, then join the table again to get both original comments and responses.
select b.*
from (
select id
from answers
where type = 1 and answer = -1
limit 2) a
join answers b on a.id = b.id or a.id = b.answer;
fiddle
To select 2 original comments of each type, you'll need to use user-defined-variable to index each original comment. The following code indexes the first original comment as 1, the second one as 2, and so on, then resets to 1 when the type changes. Finally in the final where statement filter out indices greater than 2.
select b.*, a.idx
from (
select id, #idx:=if(#type=a.type,#idx+1,1) idx, #type:=a.type
from (select id, type from answers2 where answer is null order by type) a
join (select #type:=null, #idx:=null) b) a
join answers2 b on a.id = b.id or a.id = b.answer
where a.idx <= 2;
fiddle
Store it as a separate column or even a different table if you are worried about too much data duplication. You are overthinking it.

selecting a set of rows with specific record data

I here today with a question that has left me rather confused and puzzled. Perhaps someone out there could give me a bit of assistance.
I have three table as followed. Please note that they are simplified for this question.
//table_checks//
check_id |task_id| status
1 | 1 | Done
2 | 1 | Done
3 | 1 | Done
4 | 2 | Done
5 | 2 | Not Done
6 | 2 | Not Done
7 | 2 | Not Done
8 | 2 | Done
9 | 3 | Done
10 | 3 | Done
11 | 3 | Not Done
12 | 3 | Done
//table_user//
user_id | email | type
1 | a#a.com | IN
2 | b#b.com | IN
3 | c#c.com | EX
//table_chk_usr//
check_id |user_id
1 | 1
2 | 1
3 | 1
4 | 2
5 | 2
6 | 2
7 | 2
8 | 2
9 | 3
10 | 3
11 | 3
12 | 3
Here are three tables with its relation in the table_chk_usr table.
My question is how do I query and select rows of table_user with type 'IN' from table table_user where all of users assigned task_ids in the table_checks are with the status = done.
So the expected result should be as follows
//table_user//
user_id | email | type
1 | a#a.com | IN
Since user_id with 1 has completed all task_ids with status done.
I hope this makes sense to those of you who are reading. Any help will be much appreciated.
Please Note that I am using PHP as my server side language, if that helps in any way.
I think this is what you are looking for.
select user.user_id, user.email, user.type,
sum(if(status = 'done',1, 0)) as done, count(*) as checks
from checks
join chk_user on checks.check_id = chk_user.check_id
join user on chk_user.user_id = user.user_id
group by chk_user.user_id
having done = checks
sqlFiddle
You could use a join here, but there may be a better way to do it.
SELECT * FROM table_checks
INNER JOIN table_chk_usr
ON table_checks.check_id = table_chk_usr.check_id
INNER JOIN table_user
ON table_chk_usr.user_id = table_user.user_id
WHERE table_checks.status = 'Done'
AND table_user.type = 'IN'

How do I compare 2 tables looking for missing items

I have two tables one that contains a huge list of items and another that trading for those items.
Here are examples tables:
The main table
| ID | TITLE | STATUS | TRADE |
-------------------------------
| 1 | test1 | 1 | 1 |
| 2 | test2 | 1 | 1 |
| 3 | test3 | 1 | 0 |
| 4 | test4 | 0 | 1 |
The trade table
| ID | TRADER | ITEM | URL |
------------------------------------------------------
| 1 | 2 | 1 | HTTP://www.test.com/itemOne |
| 2 | 5 | 3 | HTTP://www.test.com/itemThree |
| 3 | 5 | 4 | HTTP://www.test.com/itemFour |
Say I want to have a list of all the items that are not being traded by trader 5 and have a status of 1. So when trader 5 comes to the site they will be able to select the remaining items to trade.
Here is what I have tried:
$sql = "SELECT m.id, m.title
FROM main AS m, trade AS t
WHERE m.trade >= 1 && m.status = 1 &&
t.trader <>". mysql_real_escape_string($traderID);
This code just doesn't work. Any ideas on this?
It is not clear to me what column in Trades is an FK to Main. Below, I have assumed it is the Item column:
select m.id, m.title
from Main m
where not exists (
select *
from trade
where m.id = item
and trader = 5
)
and m.status = 1
Try this:
SELECT id, title FROM main
WHERE status = 1 AND id NOT IN
(SELECT item FROM trade WHERE trader = 5);
This will grab a list of every title in main with a status of 1, but limit the items based on a subquery which gets a list of ids already traded by trader 5 (i.e. items "not in" the list of items returned as having been traded by trader 5).
I'll leave it to you to update the query to be parameterized as needed.
Note that I'm assuming that item in trade is a foreign key to the id field in main, since you didn't specify it.

Categories