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
Related
I have searched around for an issue like I have but I have not found anything :-( , so, I have decided to open a question. I'm working on a travel agency website and I'm stuck. I have 6 tables:
1. category
2. country
3. city
4. type
5. offer
6. price
Now, the relations of each one is like this: in offer table are recorded id's of category, country, city, type and, in price table is recorded offer id. In this way, via admin panel, the process starts by creating a new offer and after that, creating prices for that offer. This is way the offer id is recorded in price table and not inverse.
What I have right now is the following:
SELECT DISTINCT
price.prFood,
offer.*
FROM
category,
country,
city,
`type`,
price
INNER JOIN offer
ON price.prOfferID = offer.offerID
WHERE offerType = typeID
AND categoryID = offerCategory
AND countryID = offerCountry
AND prOfferID = offerID
AND offerActive = '1'
AND offerCity = cityID ;
This query shows correctly, only once, every offer that has a price but, what I need is to show also offers that are active and don't have a price. So, I need a little help on the correct query to show all offers that are active, have or don't have a price.
Use left join for your price table and move where condition in on clause. I have used aliases to give short names to table, so if I have not selected proper columns, please use right aliases for the columns.
SELECT DISTINCT
p.prFood,
o.*
FROM
offer o
LEFT JOIN price p ON o.offerID = p.prOfferID
INNER JOIN category ca ON o.offerCategory = ca.categoryID
INNER JOIN country c ON o.offerCountry = c.countryID
INNER JOIN city ci ON o.offerCity = ci.cityID
INNER JOIN `type` t ON o.offerType = t.typeID
AND o.offerActive = '1'
I'm making a web application to make customers order items for anything. For that I've made a MySQL database which has the following tables:
customers
orders
order-items
products
In the customers table is all the information about the person such as:
The customer ID, for the primary key and auto increment (id)
The first name (first_name)
The last name (last_name)
The email address (email_adress)
Information about the customer (customer_info)
Example:
In the orders table is all the specific information about it such as:
The order ID, for the primary key and auto increment (id)
Which customer ordered it, linked with id field from the customers table (customer_id)
Order information (order_info)
The location where the order needs to go to (location)
When the order was created (created)
Example:
In the order-items table are all the items which every customer ordered, this is being linked by the order-id from the previous table.
The ID, for primary key and auto increment, not used for any relation (id)
The order ID, used for which product is for which order. This is linked with the id field from the orders table (order_id)
The product ID, this is used for what product they ordered, this is linked with the id field from the products table. (product_id)
The amount of this product they ordered (quantity)
Example:
In the products table is all the information about the products:
The ID, for primary key and auto incrementing, This is linked with the product_id field from the order_items table (id)
The name of the product (name)
The description of the product (description)
The price of the product (price)
Example:
The problem
Bob ordered product_id 2, times 3. Which is the sandwich with beef with the price of 2.50, which we have to multiply by 3 because it has been ordered 3 times. Which is 7.50
Bob also ordered product_id 3, times 5. Which is the sandwich with chicken with the price of 3.00, which we have to multiply by 5 because it has been ordered 5 times. Which comes out on 15.00
Now I need to sum these up. Which is 15.00 + 7.50 = 22.50
The question
How do I get the product_id linked with the actual price of the product_id? which I can then multiply by the quantity.
And then sum up all those values with the same order_id
For the first order we get product 2 (Quantity 3) and product 3 (Quantity 5), which should add 2.503 + 3.005 = 22.50
You asked, "
How do i get the product_id linked with the actual price of the product_id? Which i can then multiply by the quantity... And then sum up all those values with the same order_id."
Like this:
SELECT OI.Order_ID, Sum(OI.Quantity * P.Price) Total_Price
FROM `order-items` OI
INNER JOIN Products P
on OI.Products_Id = P.ID
GROUP BY OI.Order_ID
Expected output for sample data in question:
ORDER_ID Total_price
1 22.50
This is why I asked about sample Output. I'm not sure what columns you were trying to return so I returned just the sum total for each order.
Now what this says
Return a row for each order showing the order ID and the total_price which is the sum of (quantity ordered * price all lines for that order.
This is accomplished by looking at the order-items table (in back tic's because I'm not sure if mySQL like's dashes (-) in names.). Joining these tables based on the product_Id between the ordered items table and the price table. and then group the results by the ordered item allowing the sum to aggregate all the rows for an order times the price of the item on that line of the order together.
You can build an intermediate table that has the totals for each order, then JOIN that with the orders table to get the customerID of that order, which you join with customers to get the customer name
SELECT C.FirstName, C.LastName, Totals.Order_ID, Totals.NetCost
FROM (SELECT OI.order_id, SUM(OI.quantity * P.price) as NetCost
FROM orderitems as OI INNER JOIN products as P ON OI.products_id = P.id
GROUP BY OI.order_id
) as Totals
INNER JOIN orders as O on O.ID = Totals.order_id
INNER JOIN customers as C on C.ID = O.customer_id
And the problem #xQbert is talking about is that if your customer places an order on Monday, you raise your price on Tuesday, and run this report on Wed, the report will show a total different from what the customer saw when he approved the order. A better design would be to store orderprice in orderitem, or at least the ordertotal in orders so subsequent price changes don't affect historic orders. The former is better in case a customer wants a refund on one item.
EDIT: I mean the problem #xQbert mentions in his comment, his answer came in ahead of mine but I missed it on the refresh
EDIT 2: More explanation, as requested by #Bas
It's easiest to think of this query from the inside and work outward, so let me start with getting the prices of items.
I want to link an item in orderitem with it's price, so JOIN orderitem (I give it an alias of OI) to products (I give an alias of P) on the product ID. Product ID is called products_id in OrderItem, but just ID in products.
Once I have that, I can multiply the price from Products by the quantity in OrderItems to get a cost for just that item
Because I want the total of everything for each order, I use a GROUP BY clause on this sub query, with the thing I'm grouping by being order_id. With a GROUP BY, you usually take the field or fields you are grouping by, and some "aggregate" fields where you take the sum, or max, or average, or whatever of them, and it's the sum or whatever for all rows that are in the same group.
So at this point we have defined the query inside the parenthesis. I named that Totals, and it acts just like a real table, but it goes away when your query is over.
The next step is to combine this "totals" table with your orders table so we can look up the customer ID, and then combine it with Customers so we can look up the customer name. I used aliases for Customer and Orders (C and O respectively), but they are not necessary. In fact, this could be rewritten most if not all of the aliases. I think it makes it more readable, but if they confuse you, you could use the following instead, it's the same. I think Totals is necessary, but maybe not even that.
SELECT FirstName, LastName, Totals.Order_ID, Totals.NetCost
FROM (SELECT order_id, SUM(quantity * price) as NetCost
FROM orderitems INNER JOIN products ON products_id = products.id
GROUP BY order_id
) as Totals
INNER JOIN orders on orders.ID = Totals.order_id
INNER JOIN customers on customers.ID = orders.customer_id
Hopefully this is clear, but if not, leave more comments and I'll further explain tonight or tomorrow.
I have three tables:
Store (linked to address and category tables)
Brand (linked to category table)
Shopping mall (linked to address)
When I do a search for ac, I need to search each table and fetch all rows starting with ac.
I also need to fetch
the address and categories for each store
the address for each shopping mall
the categories for each brand
My search is using autocomplete but I don't want to display the result in one big chunck, but rather divide the result in store, brand and shopping mal.
My current solution is to execute 3 separate SQL queries, and put the result in ann array and return this.
But I don't feel doing the query this way is the most efficient way. Is there a better way to increase the speed of my search? Is there a best practice for complex search?
I am indexing things like name and address.
Currently I can only use MySQL DB.
Without knowing your exact table structure, I'd propose something similar to this:
SELECT
stores.name AS name,
addresses.street AS street,
addresses.city AS city,
'store' AS type,
GROUP_CONCAT(categories.categoryname) AS category
FROM
stores
INNER JOIN
addresses ON addresses.addressid = stores.storeid
INNER JOIN
categories AS categories.storeid = stores.storeid
WHERE
stores.name LIKE "ac%"
GROUP BY
stores.storeid
UNION
SELECT
brands.name AS name,
'-' AS street,
'-' AS city,
'brand' AS type,
GROUP_CONCAT(brandcategories.categoryname) AS category
FROM
brands
INNER JOIN
brandcategories AS brandcategories.brandid = brands.brandid
WHERE
brands.name LIKE "ac%"
GROUP BY
brands.brandsid
UNION
SELECT
malls.name AS name,
addresses.street AS street,
addresses.city AS city,
'mall' AS type,
'-' AS category
FROM
malls
INNER JOIN
addresses ON addresses.addressid = malls.mallid
WHERE
malls.name LIKE "ac%"
GROUP BY
malls.mallid
Do a SELECT... for each of the tables and UNION them. Each SELECT gets a column type, where type can be store, brand or mall. So you can distinguish it later in your PHP code.
Since every SELECT in a UNION needs the same columns, also the SELECT for e.g. brand returns an address, but it's empty.
In this example, every store/brand can have multiple categories, which get returned at once in a comma separated field (GROUP_CONCAT(categories.categoryname)).
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
Ok, so I am creating a sort of online shopping service and I have a DB that requires a field to match up against multiple other fields. They need to be stored, so that they can be ignored and set as maybe for later viewing. I know that setting up a comma delimited field is usually unwise, but I cannot figure out a better way to keep track of the matches while being able to categorize them into separate columns later on.
For eg, I have 25 products to sell and have 10 cities in which I want to sell them. Some can be shipped to 5 cites and some can be shipped to 9 cities. Now if someone searches for products in one particular city, how will only those products appear as a search result that are available for sale in that city only?
Does anyone have any better way of doing this without the comma delimited field?
I'd use about 3-4 tables:
products - having data of each product
cities - having data of relevant cities
product_cities - having relation between product and city
If a product can be shipped to 5 cities, it would have 5 rows in product_cities containing the same product_id and different city_id.
When a person searches, have something like:
SELECT pr.*
FROM cities AS c
INNER JOIN product_cities AS pc
ON c.id = pc.city_id
INNER JOIN products AS pr
ON pc.product_id = pr.id
WHERE c.name LIKE 'New York'
Two way to you will be match one column value with mutiple value using 'case statement' or in statement in where clause like:
select (case when col1>col2 then col2 else
when col1>col4 then col4 else
col1 end) as colname, col5 from tablename
or
select * form tablename where col11 in (1,2,3)
Make three different tables - one for the products you have, one for the cities you want to sell them in and one for describing where each product can be send (id, product_id, city_id).
From there, just use simple joins to select only the possible products for the selected city.
use a n:n Table:
Products Table
products
id | name
city table
cities
id | name
Mapping (unique constraint over BOTH columns, not single constraints):
shipping_information
product_id | city_id
Then you can easily select all available cities for a product, or select all products, which are shipped to a certain city.
All available cities for product 4: SELECT * FROM cities, shipping_info WHERE cities.id = shipping_info.city_id AND shipping_info.product_id = 4
All available products for city 3: SELECT * FROM products,shipping_info WHERE shipping_info.id = 3 AND shipping_info.product_id = products.id