MySQL query exclude entry depending on date - php

I need help with a MySQL query. I have 2 tables, clients and payments. The table clients has 2 fields id and name. The table payments has id, id_clients, pay_month. The clients need to pay every month a certain amount.
I want to search only the name of clients which has not paid the current month.
my query
SELECT name FROM clients WHERE id NOT IN (SELECT DISTINCT id_client FROM payments WHERE pay_month > '2014-03-15' ORDER BY pay_month DESC)
I managed to resolve my query.
I used php to store the date $today = date("Y-m-d");
SELECT DISTINCT clients.id, clients.name FROM clients WHERE clients.id NOT IN (SELECT DISTINCT id_clients FROM payments WHERE pay_month > '".$today."' ORDER BY pay_month DESC) ORDER BY clients.name ASC
Thank you everyone for your help.

Maybe something like this.
SELECT
c.name as client_name,
p.pay_month as payment_month
FROM clients c
LEFT JOIN payments p on p.id_clients = c.id
WHERE p.id IS NULL AND YEAR(p.pay_month) >= YEAR(NOW()) AND MONTH(p.pay_month) > MONTH(NOW());
if you could give us some sample data i can build a sql fiddle and do it much easier.
just edited to fix the date format/check

Related

Php MySQL Many to Many to Many condition Group By

I am creating a query between multiple many to many relationship tables in order to chain their values together. My issue is that I can't seem to figure a way to Group By the 'service' values from the 'services' sub-table in this query:
SELECT
GROUP_CONCAT(containers.container_id ORDER BY containers.container_id DESC) AS container_id,
GROUP_CONCAT(containers.container_serial ORDER BY containers.container_id DESC) AS container_serial,
GROUP_CONCAT(containers.container_index ORDER BY containers.container_id DESC) AS container_index,
invoices.*,
statuses.status,
clients.client,
GROUP_CONCAT(services.service_id ORDER BY containers.container_id DESC) AS service_id,
GROUP_CONCAT(services.service ORDER BY containers.container_id DESC) AS service
FROM containers_invoices
LEFT JOIN containers
ON containers_invoices.container_id = containers.container_id
LEFT JOIN invoices
ON containers_invoices.invoice_id = invoices.invoice_id
LEFT JOIN statuses
ON invoices.status_id = statuses.status_id
LEFT JOIN clients
ON invoices.client_id = clients.client_id
LEFT JOIN invoices_services
ON invoices.invoice_id = invoices_services.invoice_id
LEFT JOIN services
ON invoices_services.service_id = services.service_id
GROUP BY containers_invoices.invoice_id
ORDER BY invoice_id DESC
Right now my result looks something like this:
C09-65475u76u76, C08-dfsgreg345g3 - 114 - ? - Service,Service - 1000 - Sent
C09-65475u76u76, C08-dfsgreg345g3, C03-dfsdfsd, C02-sadasd - 117 - ? - Line,Line,Line,Line - 3000 - Paid
The service should show up only once and not loop as many times as the containers number that I have. I know I am close, but I can't seem to close that solution gap. Thanks for your help!
You are grouping by invoice:
GROUP BY containers_invoices.invoice_id
You should group by service from what I understand
GROUP BY services.service_id
EDIT: I guess I misunderstood the question. You'd like to keep one row per invoice but in your group_concat not list mutliple times the same value.
If it is so, you can use the DISTINCT keyword:
GROUP_CONCAT(DISTINCT services.service ORDER BY containers.container_id DESC) AS service

Sql query full join

I have 2 tables in mariadb which are treatments and payments.
Treatments: id(int(11)), treatment_name(varchar(255)), treatment_date(date)
Payments: id(int(11)), treatment_id(int(11)), payment_amount(decimal(10,2)), payment_date(date)
I want to list records from both table for a given date range, for example from 2016-01-01 to 2016-06-06
1-If the treatment is in between the given date range and has payment OR
2-if the treatment isn't in between the date range BUT has payment with the payment date is in between the given date range.
Anyone can help me for setting the query?
If I understand correctly, you don't need a full outer join. You simply need an inner join along with the correct where clause:
select t.*, p.*
from treatments t inner join
payments p
on t.id = p.treatment_id
where t.treatment_date between '2016-01-01' and '2016-06-06' or
p.payment_date between '2016-01-01' and '2016-06-06';
This can be done using UNION as follows,
SELECT * FROM Treatments WHERE treatment_date BETWEEN #01/01/2016# AND #06/06/2016#
UNION
SELECT * FROM Payments WHERE treatment_date BETWEEN #01/01/2016# AND #06/06/2016#
use this as single Query.
To give you a start, the following will join both tables, you will need to add your filtering based on the date:
SELECT *
FROM Treatments as t1, Payments as t2
WHERE t1.id = t2.treatment_id;
I believe you can do the rest on your own.

Finding the most recent record in a joined query

I have a MySQL relational database which stores customers in one table, and then another table which stores various contacts/conversations/engagements with them. See the examplar schema below:
Customers
customerId
forename
surname
Contacts
contactId
customerId
correspondenceDescription
contactDate
I need to be able to query the database and be able to access the date (contactDate) of the most recent time we have been in touch with them. I've seen a few other questions on here, but I dont seem to be able to find one which suits my needs.
Can anyone help? Many thanks.
Sure, here's a starting point. You need to get your contacts grouped by customer ID, so I'd start with this:
SELECT
MAX(contactDate), customerId
FROM
Contacts
GROUP BY
customerId
From there, you can LEFT JOIN to your customers table, and you'll be able to see the last contact date against each customer. If you are sure that each customer has at least one contact, you can swap this for INNER JOIN, which should speed things up a bit.
Try these query:
To retrieve the most recent contactDate of all customer (when you display all customer as a list):
SELECT Customers.*, max(Contacts.contactDate) as Most_Recent
from Customers left join Contacts
ON Customers.customerId = Contacts.customerId
GROUP BY Customers.customerId
ORDER BY Most_Recent desc
To retrieve the most recent contactDate of a customer (change id 1 with your customer's id):
SELECT Customers.*, Contacts.contactDate as Most_Recent
from Customers left join Contacts
ON Customers.customerId = Contacts.customerId
where Customers.customerId = 1
ORDER BY Most_Recent desc
I would generally encourage people to name columns explicity, and not to use explicit join syntax - some versions of MySQL do silly things. Aggregates are often slower than doing a order with a limit, so I'd do:
select customerId, forename, surname, contactId, correspondenceDescription, contactDate
from customer, contacts
where customer.customerId = contacts.customerId
and customer.customerId = ?
order by contactDate desc
limit 0,1

Use multiple tables to find a record MySQL

I'm sorry if the title is missleading, but I didn't know how to sum it up, sorry :(
Basically, I've made a event system that shows events that you can attend.
I got two tables
"events" and "registrations"
The events table contains all information about a single event, datetime of the event, price,, etc...
Everytime a user clicks register on an event, a record is added to the registration table.
A record looks like this: Registrationid, eventid, date, status and userid
Now I use this query to get all passed events:
SELECT * FROM events WHERE Date < CURRENT_DATE() ORDER BY Date ASC
I only want it to show previous events on the user page, if the user has actually attended the event. Is there a way I can check the registration table, and if a record exists for that event; show the event? I can do this is php, but I figured it would be possible via MySQL, though I'm not completely sure.
Is there a query that can handle the job? :)
Sure, that's a pretty simple join operation. Here's how I would do this:
select e.*
from event e join registration r
on (r.event_id=e.event_id)
where r.user_id=123 and e.date < current_date()
order by e.date asc
A couple of other tips:
Avoid using reserved words and data types as column names (e.g. "date")
The default storage engine in MySQL does not support referential integrity. If you need referential integrity, take a peek at InnoDB.
For more on joins in MySQL, check this out: https://dev.mysql.com/doc/refman/5.0/en/join.html
SELECT * FROM events e , registrations r where e.eventid = r.eventid AND e.Date < CURRENT_DATE()
SELECT e.*
FROM events e
JOIN registrations r
ON e.eventid = r.eventid
WHERE Date < CURRENT_DATE()
AND r.userid = <insert id here>
ORDER BY Date ASC
This query would give you all the fields from the events table, where a record in the registrations table has a specific user id.
Example Select with a join with your information:
SELECT * FROM events AS e WHERE e.Date < CURRENT_DATE() JOIN registration AS r ON e.id = r.eventid ORDER BY e.Date ASC
Despite other commenters' suggestion to use a JOIN (which is a decent suggestion), I think it's actually better in this case to use IN plus a subquery:
SELECT *
FROM events
WHERE eventid IN
( SELECT r.eventid
FROM registrations r
WHERE r.userid = ...
)
AND date < CURRENT_DATE()
ORDER
BY date ASC
(replacing the ... with the appropriate user-ID).
Using a JOIN, you can select the registrations rows for the userid, and then get the events data
SELECT
r.*, // Instead of *, you could specify the columns - r.userid, r.status, etc
e.* // Instead of *, you could specify the columns - e.event_name, e.Date, etc
FROM
registrations r
JOIN
events e
ON
r.eventid = e.id
WHERE
r.userid = YOUR_USERID
AND
r.status = ATTENDED
AND
e.Date < CURRENT_DATE()
ORDER BY
e.Date ASC

I need help creating a SQL query

I need to come up with a report that looks something like this:
There are 3 tables Agents, Sales and Payments. Sales and Payments are linked via the Agents table. The report is to show the total daily sales per Agent per day. It also needs to show for each day any payments the agent has made and this is to be deducted from the total sales balance such that any any point in time we can tell if the Agent owes the business or vice versa.
The way I plan to tackle this is:
Get all sales per agent per day (one query)
Get all payments per agent per day (one query)
For each Sales, agent and each day check (agents payments per agent per day) (loop)
If match is found get value and use for calculation with cumulative total
Otherwise just display appropriate sale data only with cumulative total.
I'm not sure if there is query that can make my life a bit easier. Thanks.
[Edit]
Agents Table:
id,
name,
opening_balance
Sales Table:
id,
agent_id,
amount,
customer_id,
sale_date
Payments Table:
id,
agent_id,
amount,
bank_id,
payment_date,
status
[2nd Edit]
Thanks Olaf Dietsche. The second query without the sub-select took a long time to run. About 88 secs. I also tried the first on with the sub-select and it completed in a flash however the sum(s.amount) and sum(p.amount) hold values twice what they should be.
[3rd Edit]
An agent can make multiple sales and
An agent can make multiple payments
There is no direct connection between sales and payments
Here's a first cut
select a.name, s.sale_date, sum(s.amount), sum(p.amount),
(select sum(amount)
from sales
where agent_id = a.id and sale_date <= s.sale_date) as cum_sales,
(select sum(amount)
from payments
where agent_id = a.id and payment_date <= s.sale_date) as cum_payments
from agents a
join sales s on s.agent_id = a.id
join payments p on p.agent_id = a.id
group by s.agent_id, s.sale_date
order by s.agent_id, s.sale_date
The cumulative balance would be opening_balance - cum_sales + cum_payments.
SQL Fiddle
Here is a select without subselects. This might be faster
select a.name, s.sale_date, sum(s.amount), sum(p.amount),
sum(cs.amount) as cum_sales,
sum(cp.amount) as cum_payments
from agents a
join sales s on s.agent_id = a.id
join payments p on p.agent_id = a.id
join sales cs on cs.agent_id = a.id and cs.sale_date <= s.sale_date
join payments cp on cp.agent_id = a.id and cp.payment_date <= s.sale_date
group by s.agent_id, s.sale_date
order by s.agent_id, s.sale_date
SQL Fiddle
Both are untested, since I don't have data to do so.

Categories