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
Related
I'm not a database professional, but currently working on one query (PHP->MySQL):
I have 3 tables:
'Items': id, name, link
'ItemsToUsers': id, item_id, user_id
'Users': id, email
Each 'Item' availability is submitted to regular changes which I check on fly by some algorithm.
My goal is to
1) SELECT all Items and check on fly if they are available
2) If Item is available, notify users who are monitoring it by email. For that I need to SELECT users from 'ItemsToUsers' and then get their emails from Users table.
I know how to do it in a straightforward way, but I feel that I will fall into running to many queries. (individual SELECT for every user...)
Is there a way to do it more efficiently: in one query or by changing the algorithm?
Thank you for your time!
There's not enough information to determine how an item is available. This severely impedes the ability to query item 2.
That said, let's suppose we add a "available" column to the Items table that is a tinyint of 0 for not available, 1 for available.
A query, then, which would get all email addresses for persons watching items that are available is:
SELECT u.email FROM Users AS u JOIN ItemsToUsers AS k ON k.user_id = u.id JOIN Items AS i on i.id = k.item_id WHERE i.available = 1;
Alternatively, you could use a subquery and IN.
Let's suppose you have a different table called Availability with the columns id, item_id and available, which again is a tinyint containing a 1 for available and 0 for not available.
SELECT u.email FROM Users AS u JOIN ItemsToUsers AS k ON k.user_id = u.id WHERE k.item_id IN (SELECT a.item_id FROM Availability AS a WHERE a.available = 1);
Again, without an idea of how you are getting a list of available products, it is impossible to optimize your queries for retrieving a list of email addresses.
Your steps allude to doing this in n+1 queries (where n = number of entries in the Items table):
SELECT * FROM Items; -- This is the +1 part
While iterating over that result set, you intend to determine if it's available and, if it is, to notify users who are watching it. Assuming you have a given item id and you want to select all users' email if that product id is active, then you could do this:
SELECT email FROM Users u
INNER JOIN ItemsToUsers iu ON iu.user_id = u.id
INNER JOIN Items i ON iu.item_id = i.id
WHERE i.id = {your item id}
You would be running this query for every item in your table. This is the n part.
In general you could instead generate a list of emails for all users who are watching all products that are active, after you have already determined which ones should be active:
SELECT DISTINCT email FROM Users u
INNER JOIN ItemsToUsers iu ON iu.user_id = u.id
INNER JOIN Items i ON iu.item_id = i.id
WHERE i.is_active = 1
This will get the job done in a total of 2 queries, regardless of how many users or items you have. As a bonus, this one can give you distinct emails, whereas the first solution would still need application-level code to remove duplicates returned by the multiple queries.
SELECT Items.id, Items.name, Items.link FROM Items
INNER JOIN ItemsToUsers ON ItemsToUsers.item_id = Items.items.id
INNER JOIN Users ON ItemsToUsers.user_id = Users.id ;
I am trying to create a script where employees can place orders for customers. Due to the nature of the business, 2 different employees may place an order for the same customer. I would like to print a report so these orders can be verified.
I have a customer table, and an order table, and am attempting to create a query that will list all records where there is a duplicate last name in customers table, but only if their is an order for that last name, (it is possible for a customer to exist without an order).
Either this is an obscure thing to do, or I am not searching for it correctly, as I haven't found any query that accomplishes this.
Thank you for your assistance.
customers table -
id, first_name, last_name, address, city, state, zip, phone
orders table -
id, customer_id, quantity (there is only 1 product)
Example -
there are 4 customers with the last name Johnson, and 2 records with a last name of Johnson also have orders (only the last name needs to match and is the duplicate criteria). I would like the query to print all instances of customers with the last name Johnson, (all fields) where customers.id appears in orders.customer_id
You can use a self join in order to identify duplicate last names. Something sort of like this might suit your purposes:
select c1.* from customers c1
join customers c2 on c1.last_name = c2.last_name and c1.id <> c2.id
join orders o on o.customer_id = c1.id
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
I have two tables like these
Invoice (invoice_no, invoice_date, customer_id, ...),
Customers (customer_id, customer_name, ...)
Now what I want to do is list invoices ordered by customer name.
SELECT b.customer_name, a.*
FROM Invoice a, Customers b
WHERE a.customer_id=b.customer_id
ORDER BY b.customer_name
but problem with this sql is that if there are invoices without customer_id,
how can I list those invoices first and invoices with customer_id by customer_name asc.
use LEFT JOIN instead.
"kinda" weird. How come there are some invoices that without customer? To whom are you issuing it? Anyway, here's the query.
SELECT a.*, b.* // SELECT only the columns you want
FROM Invoice a
LEFT JOIN Customers b
ON a.customer_ID = b.customer_ID
To fully gain knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
SELECT
a.*,
b.customer_name
FROM Invoice a
LEFT JOIN Customers b ON a.customer_ID = b.customerID
Use joins instead of FROM tablea, tableb.
Because this will fetch cartisian product from both tables unless you restrict them with WHERE
Use this
SELECT * FROM Invoice,customer where Invoice.customer_id=customer.customer_id ORDER BY IF(Invoice.customer_id is NULL , Invoice.customer_id, ~Invoice.customer_id) ASC
The website is intended for users to enable them joining the courses and posting their updates to these courses and also receiving the course updates made by others (imagen courses as Groups in Facebook but in my website users post updates ONLY through the courses)
When the user login to the website, he is suposed to see all the updates in the courses he already is joined in.
I have many tables in MySQL :
'updates' which have these attributes (id, account_id,course_id,datetime,content) noticing that course and account ID's are foreign keys..
'courses' which have these attributes (id,name,..)
'accounts' which have these attributes (id,full_name,...)
'accounts_courses_relationship' (account_id,course_id) , to map the relations between users and courses.
I have tried many times but the only thing I get is to show all the updates for all courses without excluding the updates from the courses that user isn't a member of, as follow:
$sql = "SELECT DISTINCT datetime, content
FROM updates
WHERE account_id != {$account_id}
ORDER BY datetime DESC
LIMIT 10";
So, How to exclude the updates from these courses?
Note: don't forget that all mappings between users and courses are registered in a table shown above..
Well i might be not seeing your problem it but how about
SELECT ... FROM updates where account_id = {$account_id}
Would't this select all updates for the current user and therefore all the updates the user is interested in?
something like this should work
select *
from updates u
join accounts_courses_relationship r on u.courseid = r.courseid
where r.account_id = {$account_id}
You have to inner join the updates and courses and accounts and accounts_courses tables.
select acr.accountid, acr.courseid, courses.name, accounts.fullname, updates.datetime, updates.content
from accounts_courses_relationship acr
inner join courses on acr.courseid=courses.courseid
inner join accounts on acr.accountid = accounts.accountid
inner join updates on updates.accountid= accounts.accountid and updates.courseid=courses.courseid
where accountid = {?}
order by updates.datetime desc
If you're interested in seeing updates to courses from other users (not you) and you're a registered user of those courses:
SELECT DISTINCT datetime, content
FROM updates
WHERE account_id != {$account_id}
and course_id in (select acr.course_id from accounts_courses_relationship acr where acr.account_id = updates.account_id)
ORDER BY datetime DESC
LIMIT 10