MySQL Conditioning Query - mysql

I was trying with writing a query to select a row from the table (attached screenshot). This is something peculiar, where * means any value. I need to select a row where Amount should be between Start Amount and End Amount and Department should be IT.
The condition for Country and Sub Department is a bit tricky. If the selected country is not in the Country column then the query should return me the record with * and same is the case with sub department.
I tried with a approach of selecting columns based on Department and amount like this
Select * from table_name where Department = 'IT'
and 1000 BETWEEN Start Amount AND End Amount
But, after this I am not sure how to get the result with below condition.
If country is not India then all * results I should get.

I believe you want something like:
SELECT *
FROM table_name
WHERE Department = 'IT'
AND 1000 BETWEEN `Start Amount` AND `End Amount`
AND country IN ('India','*')
AND `Sub Department` IN ('SD2','*')
ORDER BY country = 'India' DESC,
`Sub Department` = 'SD2' DESC
LIMIT 1

Use a union all to assign a group number in order of preference to every permitted combination of country/sub_department i.e. (India,SD1) (India,*) (*,*) then only select the rows with the lowest group number.
select t1.* from (
Select t1.* ,
if(#minGroup > groupNumber, #minGroup := groupNumber, #minGroup) minGroupNumber
from (
Select t1.*, 1 groupNumber from table_name t1
where Department = 'IT'
and 1000 BETWEEN `Start Amount` AND `End Amount`
and country = 'India'
and sub_department = 'SD1'
union all
Select t1.*, 2 groupNumber from table_name t1
where Department = 'IT'
and 1000 BETWEEN `Start Amount` AND `End Amount`
and country = 'India'
and sub_department = '*'
union all
Select t1.*, 3 groupNumber from table_name t1
where Department = 'IT'
and 1000 BETWEEN `Start Amount` AND `End Amount`
and country = '*'
and sub_department = '*'
) t1 cross join (select #minGroup := 3) t2
) t1 where groupNumber = #minGroup

Re-sending bcz, star is truncated
Select NVL(tc.Country, '*') Country_Column_name,
NVL(tsd.Sub_Dept, '*') Sub_Dept_Column_name
from table_name tn
LEFT OUTER JOIN table_country tc
ON tn.Country = tc.Country
LEFT OUTER JOIN table_sub_dept tsd
ON tn.Sub Dept = tsd.Sub Dept
where Department = 'IT'
and 1000 BETWEEN Start Amount AND End Amount
Note: Country & Sub Dpt table should have unique column and that should be used in the join.

Related

Join 2 Select Queries in a Same Table in MySql

I have a Table Name Called tbl_events and it does have following columns
Id,Event_Name, District,Branch_Type,Points
I need a Sum of Points Column Where Branch_Type=2; and Sum of Points Divided by 10 Where Branch_Type=2 after that I have to Add those Two Values And Group that Result by District and Order by Desc. I tried this Query but Seems to something wrong Can anyone help, please?
Select (t1.B_Points + t2.D_Points) as T_Points,District From
(Select Sum(Points)*.1 as B_Points ,District From tblstudents Where Branch_Type=3 group by District)t1
Left Join(Select Sum(Points) as D_points, District From tblstudents Where Branch_Type=2 group by District)t2 on
(t1.District=t2.District) Order by Desc
You need to add column alias T_Points in order by
Select (t1.B_Points + t2.D_Points) as T_Points,District
From
(
Select Sum(Points)*.1 as B_Points ,District From tblstudents
Where Branch_Type=3 group by District
)t1
Left Join
(
Select Sum(Points) as D_points, District From tblstudents
Where Branch_Type=2 group by District
)t2 on t1.District=t2.District
Order by T_Points Desc
You seem to just want conditional aggregation:
select district,
sum(case when branch_type = 3 then 0.1 * points
when branch_type = 2 then points
else 0
end) as t_points
from tblstudents
group by district;
If you want to order by the points descending, then add:
order by t_points desc
Note: This assumes that you want districts that have neither branch type. If that is not an issue, move the logic to the where clause:
select district,
sum(points * (case when branch_type = 3 then 0.1 else 1.0 end) as t_points
from tblstudents
where branch_type in (2, 3)
group by district
order by t_points desc;

Convert SumIfs Excel Function to MySQL

The formula in cell G2 "ReplenQty" is:
=SUMIFS(D:D,A:A,A2,B:B,B2,C:C,">=" & E2,C:C,"<=" &F2)
The formula in cell H2 "RpInVar" is:
=IF($A2<>$A1,ROUND(VAR(IF($A:$A=$A2,$G:$G)),2),0)
I attempted this in MySQL:
SELECT DISTINCT
Part,
Customer,
OrdDt,
OrdQty,
StartDate,
ReplenDate,
SUM(CASE WHEN Part = Part AND Customer = Customer AND OrdDt >= StartDate AND OrdDt <= ReplenDate THEN OrdQty ELSE 0 END) AS ReplenQty,
VARIANCE(CASE WHEN Part = Part AND Customer = Customer AND OrdDt >= StartDate AND OrdDt <= ReplenDate THEN OrdQty ELSE 0 END) AS RpInVar,
FROM
BeforeReplenQty
GROUP BY
Part,
Customer,
OrdDt,
OrdQty,
StartDate,
ReplenDate;
Problem is OrdQty and ReplenQty are the same and RpInVar are all 0.
This query is quite long and complicated but working on this demo: http://sqlfiddle.com/#!9/3b3334/70
One task is to do a sum where order date is between start date and replenish date.
Then get the row where part is new compared to previous row.
The first part of the query is to get the variance, the second subquery is to get the sum of Ordered qty and the sub-query at the bottom is to get the row where part column has changed.
select tab.Part,tab.Customer,tab.OrdDt,tab.OrdQty,tab.StartDate,tab.ReplenDate,tab.ReplenQty,
case when sumtab.Rnk=1 then
(select variance(ReplenQty)
from (select sum(t1.OrdQty) as ReplenQty
from BeforeReplenQty t2
inner join BeforeReplenQty t1
where t2.part=t1.part and t2.customer=t1.customer
and t2.OrdDt between t1.StartDate and t1.ReplenDate
group by t1.Part,t1.Customer,t1.OrdDt,t1.OrdQty,t1.StartDate,t1.ReplenDate) t3) else 0 end as ReplenVar
from (
select t1.*,sum(t1.OrdQty) as ReplenQty
from BeforeReplenQty t2
inner join BeforeReplenQty t1
where t2.part=t1.part and t2.customer=t1.customer
and t2.OrdDt between t1.StartDate and t1.ReplenDate
group by t1.Part,t1.Customer,t1.OrdDt,t1.OrdQty,t1.StartDate,t1.ReplenDate) tab
left join (select part,customer,orddt,rnk
from (
select t.part,t.customer,t.OrdDt,
#s:=CASE WHEN #c <> t.part THEN 1 ELSE #s+1 END AS rnk,
#c:=t.part AS partSet
from (SELECT #s:= 0) s
inner join (SELECT #c:= 'A') c
inner join (SELECT * from BeforeReplenQty
order by Part, Customer, OrdDt) t
) tab
where rnk = 1
) sumtab
on tab.part=sumtab.part and tab.customer=sumtab.customer and tab.orddt=sumtab.orddt;

Better optimized SELECT SQL query for 50,000+ records

I have a query which works great for 1000 records or less but now I need to optimize it for 50,000+ records and when I run it on that it just stalls...
Here is my code:
SELECT
b1.account_num,b1.effective_date as ed1,b1.amount as am1,
b2.effective_date as ed2,b2.amount as am2
FROM bill b1
left join bill b2 on (b1.account_num=b2.account_num)
where b1.effective_date = (select max(effective_date) from bill where account_num = b1.account_num)
and (b2.effective_date = (select max(effective_date) from bill where account_num = b1.account_num and effective_date < (select max(effective_date) from bill where account_num = b1.account_num)) or b2.effective_date is null)
ORDER BY b1.effective_date DESC
My objective is to get the latest two effective dates and amounts from one table with many records.
Here is a working answer from your SQL-Fiddle baseline
First, the inner preQuery gets the max date per account. That is then joined to the bill table per account AND the effective date is less than the max already detected.
That is then joined to each respective bill for their amounts.
select
FB1.account_num,
FB1.effective_date as ed1,
FB1.amount as am1,
FB2.effective_date as ed2,
FB2.amount as am2
from
( select
pq1.account_num,
pq1.latestBill,
max( b2.effective_date ) as secondLastBill
from
( SELECT
b1.account_num,
max( b1.effective_date ) latestBill
from
bill b1
group by
b1.account_num ) pq1
LEFT JOIN bill b2
on pq1.account_num = b2.account_num
AND b2.effective_date < pq1.latestBill
group by
pq1.account_num ) Final
JOIN Bill FB1
on Final.Account_Num = FB1.Account_Num
AND Final.LatestBill = FB1.Effective_Date
LEFT JOIN Bill FB2
on Final.Account_Num = FB2.Account_Num
AND Final.secondLastBill = FB2.Effective_Date
ORDER BY
Final.latestBill DESC
In mysql , window analytic function like row_number is not there, so we can simulate the same using variables.
The good thing is, the table is scanned only once with this approach.
A row_number is assigned to each partition which is divided based on ( account number, effective date ) and only 2 rows are selected from each partition.
select account_num,
max(case when row_number =1 then effective_date end) as ed1,
max(case when row_number =1 then amount end) as am1,
max(case when row_number =2 then effective_date end) as ed2,
max(case when row_number =2 then amount end )as am2
from (
select account_num, effective_date, amount,
#num := if(#prevacct= account_num , #num + 1, 1) as row_number,
#prevacct := account_num as dummy
from bill, (select #num:=0, #prevacct := '' ) as var
order by account_num , effective_date desc
)T
where row_number <=2
group by account_num

MySQL SELECT Query - Subtract a SUM() value with the combined total of two other SUM() values

I have two SELECT statements that give the values "TotalSales" and "VendorPay_Com". I want to be able to subtract VendorPay_Com from TotalSales within the one MySQL statement to get the value "Outstanding_Funds" but I haven't found a reliable way to do so.
These are my two statements:
Query 1:
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold';
Query 2:
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
Any help on this matter would be greatly appreciated :)
You can do it as follows :
select (select ...) - (select ...)
In your example, simply :
select
(
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold'
)
-
(
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
) AS Outstanding_Funds
Try
SELECT TotalSales-VendorPay_Comm AS Outstanding_Funds
FROM
(SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold') t1,
(SELECT SUM(Amount) AS VendorPay_Comm
FROM (SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS Amount
FROM COMMISSION
WHERE Status = 'Paid') t0) t2
Here is sqlfiddle

Is it possible for a mysql query to return true/false instead of values?

I have a table:
custID orderID orderComponent
=====================================
1 123 pizza
1 123 wings
1 234 breadsticks
1 239 salad
2 456 pizza
2 890 salad
I have a list of values - pizza, wings, breadsticks, and salad. I need a way to just get a true/false value if a customer has at least one record containing each of these. Is that possible with a mysql query, or do I just have to do a select distinct(orderComponent) for each user and use php to check the results?
If you are just looking to see if the customer has ordered all items, then you can use:
select t1.custid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
See SQL Fiddle with Demo
If you want to expand this out, to see if the custid has ordered all items in a single order, then you can use:
select t1.custid,
t1.orderid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, orderid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid, orderID
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
and t1.orderId = t2.orderid
See SQL Fiddle with Demo
If you only want the custid and the true/false value, then you can add distinct to the query.
select distinct t1.custid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
See SQL Fiddle with Demo
Or by custid and orderid:
select distinct
t1.custid,
t1.orderid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, orderid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid, orderID
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
and t1.orderId = t2.orderid
See SQL Fiddle with Demo
select case when
count(distinct orderComponent) = 4
then 'true'
else 'false'
end as bool
from tbl
where custID=1
Here's one approach. This approach does not require an inline view (derived table), and can be effective if you want to include flags for multiple conditions:
EDIT:
This returns custID that has a row for all four items:
SELECT t.custID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
FROM mytable t
GROUP BY t.custID
HAVING has_all_four = 4
ORIGINAL ANSWER:
(This checked for a customer "order" that had all four items, rather than just a "custID".)
SELECT t.custID
, t.orderID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
-- , MAX(IF(t.orderComponent='breadsticks',1,0)) AS has_breadsticks
-- , MAX(IF(t.orderComponent='pizza',1,0)) AS has_pizza
-- , MAX(IF(t.orderComponent='salad',1,0)) AS has_salad
-- , MAX(IF(t.orderComponent='wings',1,0)) AS has_wings
FROM mytable t
GROUP BY t.custID, t.orderID
HAVING has_all_four = 4
That will get the "orders" that have all four items. If you want to return just values for custID, then use the query above as an inline view (wrap it in another query)
SELECT s.custID
FROM (
SELECT t.custID
, t.orderID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
FROM mytable t
GROUP BY t.custID, t.orderID
HAVING has_all_four = 4
) s
GROUP BY s.custID
#EmmyS: you can do it both ways.
If you want to check using MySql use:
SELECT #rowcount:=COUNT(*) FROM orderComponent Where (Your Conditions);
IF (#rowcount > 0) THEN
'True'
ELSE
'False'
END IF