multiple where conditions with joining - php

I am stuck in a problem since long.
I have a table for orders of customers, I want to get 4 types of results like
1st: All orders with status=place
then 2nd: All orders with status=place and customer is new (no previous record in order table of this customer),
then 3rd: All orders with status=place and customer have at least 1 order delivered and never returned previous order ,
then 4th: All orders with status=place and customer have atleast 1 order with status=returned
Query for 1st step is working fine, but i got no idea to get other results.I know its like an assignment but i need help.
MY Try for 1st step
SELECT o.order_id, o.customer_id, o.order_status_id,
FROM `order` o
WHERE (o.order_status_id = '1'
AND o.payment_code <> 'paytabs'
AND o.payment_code <> 'pp_express')
ORDER BY o.order_id DESC
This give me perfect result for step one.I am using OpenCart 2.2.0.0
Database Structure
|order_id |status | payment_code |customer_id |
|---------|-------|--------------|------------|
| 10 | place | cod | 5 |
| 11 | delvr | cod | 4 |
| 12 | return| pp_express | 5 |
| 13 |process| paytabs | 2 |
Any help or suggestion will be appreciated.
Ask me for anything you need more.

Not sure to understand your DB structure, but I will try...
Ad 2:
SELECT o.order_id, o.customer_id, o.order_status_id,
FROM `order` o
WHERE (o.order_status_id = '1'
AND o.payment_code <> 'paytabs'
AND o.payment_code <> 'pp_express')
AND o.customer_id NOT IN (SELECT o2.customer_id from order o2 WHERE o2.order_id != o.order_id AND o2.customer_id = o.customer_id)
ORDER BY o.order_id DESC
Accordingly, ad 4:
SELECT o.order_id, o.customer_id, o.order_status_id,
FROM `order` o
WHERE (o.order_status_id = '1'
AND o.payment_code <> 'paytabs'
AND o.payment_code <> 'pp_express')
AND o.customer_id IN (SELECT o2.customer_id from order o2 WHERE o2.order_status = 'returned')
ORDER BY o.order_id DESC
Now for 3:
SELECT o.order_id, o.customer_id, o.order_status_id,
FROM `order` o
WHERE (o.order_status_id = '...?')
AND o.customer_id NOT IN (SELECT o2.customer_id from order o2 WHERE o2.order_status = 'returned')
AND o.customer_id IN (SELECT o3.customer_id from order o3 WHERE o3.order_status = 'delivered')
ORDER BY o.order_id DESC
BTW: I strongly recommend to rename table "order" since "order" is an SQL keyword.

I think you should use Union when you want to do that with one query.
Other ways, when same customer meets 2 contidions, then you will only see one.
https://www.w3schools.com/sql/sql_union.asp

For the 2nd query : you can just add an AND clause to your SQL :
AND user_id = 0
Assuming a new order is inserted with user_id = 0 if this is a new user

queries:
the queries are as per your question u asked and you orders table structure(i am considering that you have not created any column like created_at and updated_at).
select * from orders where status = 'place';
select orders.order_id ,orders.customer_id from orders where status = 'place' GROUP BY order_id, customer_id HAVING COUNT(customer_id) = 1;
select a.order_id, a.customer_id from orders a where a.status in (select b.status from orders b where a.order_id = b.order_id and status <> 'return') and a.status = 'place' GROUP BY a.order_id, a.customer_id HAVING COUNT(a.customer_id) >= 1;
select a.order_id, a.customer_id from orders a where a.status in (select b.status from orders b where a.order_id = b.order_id and status = 'return') and a.status = 'place' GROUP BY a.order_id, a.customer_id HAVING COUNT(a.customer_id) >= 1

Related

Multiple LEFT JOINS with Multiple COUNT() count all colum

I have 4 tables.
table groups
| ID | NAME |
1 Premium
2 Silver
table user
| ID | group_id | NAME |
1 1 Serhan
2 2 Farhat
table user_statistics
| ID | user_id | TYPE |
1 1 1
2 2 0
table votes
| ID | user_id | VOTE |
1 1 1
2 2 0
3 1 0
I created an sql query to retrieve user details who is in same group. It's worked! Then I want to retrieve any of vote that have been voted to user in groups. I want to count the vote. So basically I've made this sql query.
global $conn;
$res_groups = array();
$stmt = $conn->prepare("
SELECT * FROM groups
");
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
while ($group = $stmt->fetch()){
$groups = array();
$groups['id'] = $group['id'];
$groups['name'] = $group['name'];
$user_arr = array();
$stmts = $conn->prepare('
SELECT l.*,
(SELECT MAX(ls.date) from user_statistics ls WHERE ls.user_id = l.id GROUP BY ls.user_id) as ls_date,
(SELECT SUM(IF(ls.type="0", ls.type, 0)) FROM user_statistics ls WHERE ls.user_id = l.id GROUP BY ls.user_id) as ls_us,
(SELECT SUM(IF(ls.type="1", ls.type, 0)) FROM user_statistics ls WHERE ls.user_id = l.id GROUP BY ls.user_id) as ls_uk,
(SELECT COUNT(*) FROM user_statistics WHERE type="1" AND ls.user_id = l.id GROUP BY ls.user_id) as totals,
(SELECT COUNT(*) FROM votes v WHERE v.vote=0 AND confirm=0 AND v.user_id = l.id) as badvote,
(SELECT COUNT(*) FROM votes v WHERE v.vote=1 AND confirm=0 AND v.user_id = l.id) as goodvote
FROM user l
LEFT JOIN
user_statistics ls on l.id = ls.user_id
LEFT JOIN votes v on v.user_id = l.id
WHERE l.group_id = '.$groups['id'].' AND status = 1
GROUP BY l.id,ls.user_id
');
$stmts->execute();
$stmts->setFetchMode(PDO::FETCH_ASSOC);
while ($usr = $stmts->fetch()){
$totalvote=($usr['badvote']+$usr['goodvote']);
if($totalvote>0){
$badvote=bcdiv($usr['badvote']*100/$totalvote,1,2);
$goodvote=bcdiv($usr['goodvote']*100/$totalvote,1,2);
}else{
$badvote=0;
$goodvote=0;
}
$votes[] = array(
"count" => $usr['badvote'],
"percent" => $badvote
);
$votes[] = array(
"count" => $usr['goodvote'],
"percent" => $goodvote
);
$user_arr[] = array(
"id" => $usr['id'],
"group_id" => $usr['group_id'],
"name" => $usr['name'],
"votes_summary" => $votes
);
}
$groups['list'] = $user_arr;
$res_groups[] = $groups;
}
All code seems work unless one thing. The VOTE is always return to count all column in my database VOTES and apply the data to all of my user. What I want is to get how many vote that each user get based on vote type GOOD or BAD.
Any help will be nice.
Looking to your code you could refactor your query avoiding select subquery one for each row and using two subquery with group by in join.
You have also the same code for bad and good vote could be you need different code for obtain different values
SELECT l.*
, t1.ls_date
, t1.ls_us
, t1.ls_uk
, t2.totals
, t2.badvote
, t2.goodvote
FROM user l
INNER JOIN (
SELECT ls.user_id
, MAX(ls.date) ls_date
, SUM(IF(ls.type="0", ls.type, 0)) ls_us
, SUM(IF(ls.type="1", ls.type, 0)) ls_uk
from user_statistics ls
GROUP BY ls.user_id
) t1 on t1.user_id = l.id
LEFT JOIN (
SELECT v.user_id
, sum( case when type="1" then 1 else 0 end ) totals
/* these are the same */
, sum ( case when v.vote=1 AND confirm=0 then 1 else 0 END ) badvote
/* these are the same */
, sum ( case when v.vote=1 AND confirm=0 then 1 else 0 END ) goodvote
FROM votes v
) t2 ON t2.user_id = l.id
WHERE l.group_id = '.$groups['id'].'
AND status = 1
And you should avoid the use of PHP var in SQL (you are at risk for SQL injection). For this you should take a look at your db driver for prepared statement and binding value, or at least be sure you sanitize properly the php var content

MySQL Query to get Data of Specific Item by All Months

Okay I have a table 3 Tables (Orders, Order_details, Products)
Orders
id | order_date
1 | March-01-13
2 | March-02-13
3 | April-01-13
4 | May-01-13
5 | June-01-13
and so on.....
Order_Details
id | order_id | product_id | total_price
1 1 1 100 /*mouse*/
2 1 3 200 /*monitor*/
3 2 2 50 /*keyboar*/
4 2 3 200 /*monitor*/
and so on....
Products
id | title
1 mouse
2 keyboard
3 monitor
and so on...
And here is my SQL Query that giving unexpected output
SELECT title, SUM(total_price) as total_price, orders.order_date as date
FROM products
LEFT JOIN order_details
ON order_details.product_id=products.id
LEFT JOIN orders
ON orders.id=order_details.order_id
WHERE title='monitor' /*this is just a try, prod_id should be the one*/
GROUP BY MONTH(date)
ORDER BY total_price DESC LIMIT 10
What I want to get is the total_price of product_id in all months
Expected Output
title | total_price | date
monitor 400 March
When using a GROUP BY, all of the fields in the SELECT list need to either be aggregated, or be part of the GROUP BY. So try adding the 'title' to the group by, and adding the MONTH function to the order_date in the SELECT list as follows:
SELECT title, SUM(total_price) as total_price, MONTH(orders.order_date) as date
FROM products
LEFT JOIN order_details ON order_details.product_id=products.id
LEFT JOIN orders ON orders.id=order_details.order_id
WHERE title='monitor'
GROUP BY title, date
ORDER BY total_price DESC LIMIT 10
This will get the total_price for each product for each month.
Do you want something like this?
SELECT p.title, SUM(total_price) as total_price
FROM products p LEFT JOIN
order_details od
ON od.product_id = p.id LEFT JOIN
orders o
ON o.id = od.order_id
GROUP BY p.title
ORDER BY total_price DESC
LIMIT 10;
I don't see why your sample output would have a month in it.

mysql search 2 tables with overlap

i have 2 tables, see below - profiles is my main/master table
profiles invoices
____________ ___________________
|id Name | |profileid paid |
|============| |===================|
|1 Abraham | | 2 unpaid |
|2 Martin | | 3 unpaid |
|3 John | | 3 paid |
|____________| |___________________|
as can be seen, abraham has 0 invoices, martin has 1 unpaid invoice, and john has 2 invoices; 1 paid, 1 unpaid.
i want to search for:
all profiles with paid invoices (john)
all profiles with unpaid invoices (john & martin)
all profiles with both paid AND unpaid invoice(s) (john)
i can do 1 and 2 fine but im having a problem with step 3.
here is my query for 1;
$query = "SELECT DISTINCT profiles.name
FROM profiles LEFT JOIN invoices ON (profiles.id=invoices.profileid)
AND (invoices.paid='paid' OR invoices.paid='unpaid')
WHERE
IFNULL(invoices.paid, '') LIKE 'paid';
here is my query for 2;
$query = "SELECT DISTINCT profiles.name
FROM profiles LEFT JOIN invoices ON (profiles.id=invoices.profileid)
AND (invoices.paid='paid' OR invoices.paid='unpaid')
WHERE
IFNULL(invoices.paid, '') LIKE 'unpaid';
here is my query for 3;
$query = "SELECT DISTINCT profiles.name
FROM profiles LEFT JOIN invoices ON (profiles.id=invoices.profileid)
AND (invoices.paid='paid' OR invoices.paid='unpaid')
WHERE
IFNULL(invoices.paid, '') LIKE 'paid'
AND IFNULL(invoices.paid, '') LIKE 'unpaid'
;
as mentioned, 1 & 2 work fine, but 3 gives me 0 results.
any help is much appreciated. thanks
You need to select the invoices table 2 times, in order to get where someone has both paid and unpaid. Try something like -
SELECT DISTINCT profiles.name
FROM profiles
LEFT JOIN invoices i1 ON (profiles.id=i1.profileid)
AND (i1.paid='paid')
LEFT JOIN invoices i2 ON (profiles.id=i2.profileid)
AND (i2.paid='unpaid')
WHERE
IFNULL(i1.paid, '') LIKE 'paid'
AND IFNULL(i2.paid, '') LIKE 'unpaid';
see this sqlfiddle example - http://sqlfiddle.com/#!2/ee4e2/4
One possibility is a sub query to count the distinct invoice types associated with a profile
SELECT `profiles`.`name`
FROM `profiles`
WHERE (
SELECT count( DISTINCT `subinvoices`.`paid` )
FROM `invoices` AS `subinvoices`
WHERE `profiles`.`id` = `subinvoices`.`profileid`
AND (`subinvoices`.`paid` = 'paid' OR `subinvoices`.`paid` = 'unpaid')
) = 2
The easiest way to do this is with aggregation:
select p.*, coalesce(InvoiceInfo, 'NONE')
from profiles p left outer join
(select profileid,
(case when sum(paid = 'PAID') > 0 and sum(paid = 'UNPAID') > 0 then 'BOTH'
when sum(paid = 'PAID') > 0 then 'PAID-ONLY'
when sum(paid = 'UNPAID') > 0 then 'UNPAID-ONLY'
end) as InvoiceInfo
from invoices i
)
on p.id = i.profileid
This allows you to get all three types of information at once. You can count the people in each group, for instance, by doing:
select coalesce(InvoiceInfo, 'NONE'), count(*)
from profiles p left outer join
(select profileid,
(case when sum(paid = 'PAID') > 0 and sum(paid = 'UNPAID') > 0 then 'BOTH'
when sum(paid = 'PAID') > 0 then 'PAID-ONLY'
when sum(paid = 'UNPAID') > 0 then 'UNPAID-ONLY'
end) as InvoiceInfo
from invoices i
)
on p.id = i.profileid
group by coalesce(InvoiceInfo, 'NONE')

Mysql query ( LINK tickets, employee , cats , comments ) using JOIN

here is my tables
Tickets
tic_id,
tic_cat
tic_priority
tic_cus
tic_date
tic_title
tic_msg
tic_files
tic_emp
tic_moved
tic_statue
tic_rate
Employee
emp_id
emp_name
emp_username
emp_password
emp_cat
emp_special
emp_lastlogin
emp_session
emp_code
emp_statue
emp_master
emp_ip
Cats
cat_id
cat_type
cat_name
cat_statue
cat_delete
cat_date
cat_ip
cat_options
Comments
com_id
tic_id
cus_id
emp_id
com_msg
com_time
com_ip
com_statue
And I need the result as
tic_id | tic_cat | cat_name | tic_title | tic_statue | tic_priority | tic_msg | emp_name | comments_row | last_comment |
I Make this query but i have 2 problems
Query Is
SELECT
tickets.tic_id
,tickets.tic_cat
,cats.cat_name
,tickets.tic_title
,tic_statue
,tic_priority
,tickets.tic_msg
,employee.emp_name
,count(comments.com_id)
,( SELECT comments.com_msg
from comments
order by com_id DESC limit 1 )
AS last_comment
FROM tickets
LEFT JOIN employee
on (tickets.tic_emp = employee.emp_id)
LEFT join cats
on (tickets.tic_cat = cats.cat_id)
LEFT JOIN comments
on(tickets.tic_id = comments.tic_id)
WHERE tic_cus=2 /* 2 -> This Is Customer Id */
GROUP BY comments.tic_id
My Problems Is
i have 3 Result In Database To Customer Number 2 -> only show 2 results
i want to get Last Comment -> the 2 Result have the same last comment
How Can i do this Query With Out This 2 Errors
Edit The Post After New Query
Problem number Two Solved Using This Query
SELECT
tickets.tic_id
,tickets.tic_cat
,cats.cat_name
,tickets.tic_title
,tic_statue
,tic_priority
,tickets.tic_msg
,employee.emp_name
,count(comments.com_id)
,( SELECT comments.com_msg
from comments
WHERE tickets.tic_id = comments.tic_id
order by com_id DESC limit 1 )
AS last_comment
FROM tickets
LEFT JOIN employee
on (tickets.tic_emp = employee.emp_id)
LEFT join cats
on (tickets.tic_cat = cats.cat_id)
LEFT JOIN comments
on(tickets.tic_id = comments.tic_id)
WHERE tic_cus=2
GROUP BY comments.tic_id
Solved
SELECT
tickets.tic_id
,tickets.tic_cat
,cats.cat_name
,tickets.tic_title
,tic_statue
,tic_priority
,tickets.tic_msg
,employee.emp_name
,count(comments.com_id)
,( SELECT comments.com_msg
from comments
WHERE tickets.tic_id = comments.tic_id
order by com_id DESC limit 1 )
AS last_comment
FROM tickets
LEFT JOIN employee
on (tickets.tic_emp = employee.emp_id)
LEFT join cats
on (tickets.tic_cat = cats.cat_id)
LEFT JOIN comments
on(tickets.tic_id = comments.tic_id)
WHERE tic_cus=2
GROUP BY tickets.tic_id
1) Can you show some data in these tables to demonstrate? In other words, how do you know you should have three records? Does select * from tickets where tic_cus = 2 by itself return 3 records?
2) You need to filter the comments subquery by ticket. I would also recommend having the comment count in a subquery as well and leave out the GROUP BY altogether:
,( select count(comments.com_id)
from comments
where comments.tic_id = tickets.tic_id) as comment_count
,( select comments.com_msg
from comments
where comments.tic_id = tickets.tic_id
^^^^^^^ filter by ticket so not last of ALL comments
order by com_id DESC limit 1) as last_comment

Tough Mysql Query

I got a skill test for a quick mysql query. I am given the tables:
Orders OrderItems
----------------------------------------
id id
date order_id(Orders.id)
shipping_amount product_id
order_status price
customer_id quantity
I need to show Orders id and totals (including shipping amount) and records prior to June 1, 2003.
output should be...
| OrderID | OrderTotal |
+-----------+------------+
| 13230 | $55.00 |
| 54455 | $40.00 |
| 59694 | $33.04 |
| 39495 | $21.05 |
The hint is to use Group by or subselect. I have the following statement so far but not sure what to do next.
Select id AS OrderId,***(not sure what to do here)
from Orders join OrderItems on Orders.id=OrderItems.id
I don't have access to a mysql database to test, but I would imagine it looks something like this:
select
o.id OrderID,
(select sum(oi.price * oi.quantity) from order_items oi where oi.order_id = o.id) + o.shipping_amount OrderTotal
from
orders o
where
o.date < str_to_date('2003-06-01', '%Y-%m-%d');
I'd say it must look like this:
SELECT O.ID as OrderID, SUM(OI.price * OI.quantity) AS OrderTotal
FROM Orders O
INNER JOIN OrderItems OI ON O.id = OI.order_Id
WHERE date < '2003-06-01'
GROUP BY O.id
ORDER BY SUM(price * quantity) DESC
Not sure how to format dates in MySQL though or if you can order by an agregate function in this version but I'm pretty sure this is a good start.

Categories