MySQL Query Issues with Math not resulting in expected output - mysql

Overview:
I built an application that I run locally which allows me to keep track of my kids chores and behaviors that they exhibit on a daily basis. This system has negative and positive behaviors I can assign to them which correspond to a point value on a 100 point scale.
Logic:
The query only looks at the current day to calculate the points. If ratings were received the day prior, those will not play into their daily total.
100 points is the maximum a child can have for the day, even if their ratings cause them to exceed this, it will always return as 100.
If they don't have any ratings for the day (either positive or negative), it will default their points to the starting point 100.
When they receive points, their total will adjust accordingly, either going up or down based on the value set for the behavior.
Scenarios:
New day without any ratings means the child starts at 100 points. They receive a negative behavior that has a -3 value. This would return their totalPoints as 97.
The above child then receives a positive rating worth 2 points which brings them up to 99 for their totalPoints.
They receive another positive rating worth 5 points. Since we max out at 100, we would return their totalPoints as 100, regardless of how much it exceeded 100.
Issue:
I built the query and thought everything was working fine but there seems to be a slight math issue with it. When the child received a -3 point rating it brought them to 97 which was expected. I then gave them a positive 4 and it brought their score to 99 instead of 100 like I would have expected.
Query:
SELECT c.id,
c.NAME,
Date_format(From_days(Datediff(CURRENT_DATE, c.age)),
'%y Years %m Months %d Days') AS age,
c.photoname,
c.photonamesmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
) >= (
SELECT
settingvalue
FROM
settings
WHERE
settingname = 'MaxPoints') ) THEN 100
WHEN ( Sum(t.points) <= 0 ) THEN ( (SELECT settingvalue
FROM settings
WHERE settingname =
'MaxPoints')
+ Sum(t.points) )
ELSE ( (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints') -
Ifnull(Sum(t.points), (SELECT
settingvalue
FROM settings
WHERE
settingname = 'MaxPoints')) )
END
FROM behaviorratings AS r
JOIN behaviortypes AS t
ON r.behaviorid = t.behaviortypeid
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionname
FROM behaviordefinitions AS d
WHERE totalpoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Fiddle:
Here is a link to the SQL fiddle: http://sqlfiddle.com/#!9/fa06c/1/0
The result I expect to see for Child 2 (Brynlee) is 100 not 99.
She started with 100, received a -3 and the received a +4. While I know the math for this order of operations is correct, I need to it to be tweaked to reflect how I expected it to be reflected. 100 - 3 = 97 and then 97 + 4 = 101 (We max out at 100 so 100 would be the totalPoints.

Try this
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0
) + (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints') >= (
SELECT
settingValue
FROM
settings
WHERE
settingName = 'MaxPoints') ) THEN 100
WHEN ( Sum(t.points) <= 0 ) THEN ( (SELECT settingValue
FROM settings
WHERE settingName =
'MaxPoints')
+ Sum(t.points) )
ELSE ( (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints') -
Ifnull(Sum(t.points), (SELECT
settingvalue
FROM settings
WHERE
settingName = 'MaxPoints')) )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Basically, using
WHEN ( Ifnull(Sum(t.points), (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
)
will only give you 100 when sum(t.points) is null. To get total points you need to do
Ifnull(Sum(t.points), 0) + (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
This sql may make it easier to look at
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0) + #maxPoints > #maxPoints ) THEN 100
ELSE ( Ifnull(Sum(t.points), 0) + #maxPoints )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Using 50 as starting point:
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SET #startingPoint := 50;
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0) + #startingPoint > #maxPoints ) THEN 100
ELSE ( Ifnull(Sum(t.points), 0) + #startingPoint )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Sql for applying capping once total points exceeding limitation
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SET #startingPoint := 50;
SELECT
c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(DATEDIFF(CURRENT_DATE, c.age)), '%y Years %m Months %d Days') AS age,
c.photoName,
c.photoNameSmall,
(
select x.tp
from
(
SELECT t.childid,
#rn:=CASE WHEN #cid <> t.childid THEN 0 ELSE #rn+1 END AS rn,
#startingPoint + #tp:= CASE
WHEN #cid <> t.childid
THEN ifnull(t.points, 0)
ELSE (
case when #startingPoint + t.points + #tp > #maxPoints
then #maxPoints - #startingPoint
else t.points + #tp end)
END AS tp,
#cid:=t.childid AS clset,
t.timestamp
FROM
(SELECT #tp:= -1) p,
(SELECT #rn:= -1) n,
(SELECT #cid:= -1) cd,
(
SELECT r.childid, t.points, r.timestamp
FROM behaviorRatings AS r
JOIN behaviorTypes AS t ON r.behaviorID = t.behaviorTypeID
ORDER BY r.childid, r.timestamp
) t
) x
where x.childid = c.id AND Date_format(x.timestamp, '%Y-%m-%d') = Curdate()
order by x.childid, x.rn desc
limit 1
) AS totalPoints,
(
SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max
) AS behaviorRating
FROM children AS c

Don't make things more complicated than they should be. Choose the right language for your task. In you case it's PHP:
$query = "select settingValue from settings where settingName = 'MaxPoints'";
$result = $this->db->query($query);
$row = $result->fetchAssoc();
$maxPoints = $row['settingValue'];
$query = "select * from children";
$result = $this->db->query($query);
$children = array();
while ($row = $result->fetchAssoc()) {
$row['totalPoints'] = $maxPoints;
$children[$row['id']] = $row;
}
$query = "
select c.id, coalesce(bt.points, 0) as points
from children c
join behaviorRatings br on br.childID = c.id
join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
where date(br.timestamp) = current_date()
order by c.id, br.timestamp
";
$result = $this->db->query($query);
while ($row = $result->fetchAssoc()) {
$childId = $row['id'];
$totalPoints = $children[$row['id']]['totalPoints'];
$totalPoints = $totalPoints + $row['points'];
$totalPoints = min($totalPoints, $maxPoints);
$children[$row['id']]['totalPoints'] = $totalPoints;
}
var_dump($children);
All the logic to get the total points is in the last loop. Now compare it to your query.
However - if you change the rules, allowing to exceed the limit during the day and cut the points only at the end of the day, this could be done in a single query:
select c.*, sub.totalPoints, bd.definitionName
from (
select c.id, least(100+coalesce(sum(bt.points), 0), mp.settingValue) as totalPoints
from children c
join settings mp on settingName = 'MaxPoints'
left join behaviorRatings br
on br.childID = c.id
and date(br.timestamp) = current_date()
left join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
group by c.id
) sub
join children c on c.id = sub.id
join behaviorDefinitions bd on sub.totalPoints between bd.min and bd.max
http://sqlfiddle.com/#!9/fa06c/71
While it is not a simple query, it is by far not as complex as your try. The accepded solution is doing the same ignoring the rule, that total points have to be cut to 100 every time points are gained (Sum(t.points)).
As I wrote in the comments: To follow that rule, you need some kind of iteration. There is a trick in MySQL using user variables:
select c.id, c.name, sub.totalPoints, bd.definitionName
from (
select sub.childId, sum(sub.cuttedPoints) + sp.settingValue as totalPoints
from (
select
#points := coalesce(bt.points,0) as points,
#lastTotalPoints := case when (c.id = #childId)
then #totalPoints
else sp.settingValue
end lastTotalPoints,
#totalPoints := least(#lastTotalPoints + #points, mp.settingValue) as totalPoints,
#totalPoints - #lastTotalPoints as cuttedPoints,
#childId := c.id as childId
from children c
join settings sp on sp.settingName = 'StartPoints'
join settings mp on mp.settingName = 'MaxPoints'
left join behaviorRatings br
on br.childID = c.id
and date(br.timestamp) = current_date()
left join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
cross join (select #childId := null) init_var
order by c.id, br.timestamp
) sub
join settings sp on sp.settingName = 'StartPoints'
group by sub.childId
) sub
join children c on c.id = sub.childId
join behaviorDefinitions bd on sub.totalPoints between bd.min and bd.max
Result (Brynlee behaviour: +4 -3 +4 -3):
| id | name | totalPoints | definitionName |
|----|---------|-------------|------------------------|
| 2 | Brynlee | 97 | Having an amazing day! |
| 1 | Maya | 100 | Having an amazing day! |
Brynlee gets 97 points as expected (+4 => 100, -3 => 97, +4 => 100, -3 => 97)
http://sqlfiddle.com/#!9/751c51/28
If you change the new setting "StartPoints" to 50 you will get:
| id | name | totalPoints | definitionName |
|----|---------|-------------|------------------|
| 2 | Brynlee | 52 | Not looking good |
| 1 | Maya | 50 | Not looking good |
Here Brynlee gets 52 points because the limit of 100 was never reached (+4 => 54, -3 => 51, +4 => 55, -3 => 52).
http://sqlfiddle.com/#!9/db020/13
This works because of MySQLs processing order. But this order depends on internal implementation of MySQL. This implementation may be changed in future versions without any warning. I fact - MySQL developers explicitly warn of using user variables that way.
As a general rule, other than in SET statements, you should never
assign a value to a user variable and read the value within the same
statement. For example, to increment a variable, this is okay:
SET #a = #a + 1;
For other statements, such as SELECT, you might get the results you
expect, but this is not guaranteed. In the following statement, you
might think that MySQL will evaluate #a first and then do an
assignment second:
SELECT #a, #a:=#a+1, ...;
However, the order of evaluation for expressions involving user
variables is undefined.
(User-Defined Variables)
I only use "tricks" like that for one-way reports - But never in production code.
So my suggestion is: Change the rules or use a procedural language (PHP).

Related

How to group by date

Below I cannot do Group by Date the following figures.
I have tried to put Group By in different lines, but not working.
SELECT SUM(a.NetAmount) AS TotalDonation
FROM (
SELECT
(
CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE
bt.BalanceTransactionNet * (SELECT TOP 1 ExrateValue FROM Exrate WHERE ExrateDate < bt.BalanceTransactionCreated AND bt.BalanceTransactionCurrencyID = CurrencyID ORDER BY ExrateDate Desc)
END
) AS NetAmount
FROM Charge as ch
JOIN BalanceTransaction as bt ON (ch.BalanceTransactionID = bt.BalanceTransactionID)
WHERE ch.ChargeCreatedDate BETWEEN '3-1-2019' AND '3-31-2019'
) AS a
I wanted to see:
Days Total Amount
March 1 xxxx
March 2 xxxx
March 3 xxx
MySQL does not use TOP. Use LIMIT:
SELECT ChargeCreatedDate, SUM(netamount)
FROM (SELECT ch.ChargeCreatedDate,
(CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE bt.BalanceTransactionNet * (SELECT e.ExrateValue
FROM Exrate e
WHERE e.ExrateDate < bt.BalanceTransactionCreated AND
e.CurrencyID = bt.BalanceTransactionCurrencyID
ORDER BY ExrateDate Desc
LIMIT 1
)
END) AS NetAmount
FROM Charge ch JOIN
BalanceTransaction bt
ON ch.BalanceTransactionID = bt.BalanceTransactionID
WHERE ch.ChargeCreatedDate BETWEEN '2019-03-01' AND '2019-03-31'
) chtbt
GROUP BY ChargeCreatedDate;
If you happen to be using SQL Server, you can replace the LIMIT 1 with FETCH FIRST 1 ROW ONLY.
The following code will hopefully display what you are looking for
SELECT a.Days AS Days, SUM(cast(a.NetAmount as decimal(16,9))) AS TotalDonation
FROM (
SELECT
(
CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE
bt.BalanceTransactionNet * (SELECT TOP 1 ExrateValue FROM Exrate WHERE ExrateDate < bt.BalanceTransactionCreated AND bt.BalanceTransactionCurrencyID = CurrencyID ORDER BY ExrateDate Desc)
END
) AS NetAmount,
ch.ChargeCreatedDate as Days
FROM Charge as ch
JOIN BalanceTransaction as bt ON (ch.BalanceTransactionID = bt.BalanceTransactionID)
WHERE ch.ChargeCreatedDate BETWEEN '3-1-2019' AND '3-31-2019'
) AS a GROUP BY a.Days
This should be sufficient. You need to SELECT the desired value in the query in order to get it to show up. Also when using the SUM() function you need to specify what the group value will be.

user defined variable to store ranking gives wrong values if order by

mysql table: work
|id|user_id|created_at|realization|
I have been working on a sql query which calculates performance (realisation today / realization on the first day of the month) and sortes records based on performance.
Expected result:
|ranking|performance|user|
|1|0.88|36|
|2|0.712444111|444|
|3|0.711|1|
|4|0.33333|9|
|5|0.1006|29|
returned result:
|ranking|performance|user|
|4|0.88|36|
|2|0.712444111|444|
|5|0.711|1|
|3|0.33333|9|
|1|0.1006|29|
Here is my query:
SET #ranking := 0;
SELECT
#ranking := #ranking + 1 as ranking,
w1.user_id,
IFNULL(ROUND(w2.realization / w1.realization), 4), 0) AS performance
FROM work w1
JOIN (
SELECT min(created_at) AS first_month, max(created_at) AS last_month, user_id
FROM work
WHERE (DATE_FOMAT(NOW(), '%Y-%m') = DATE_FORMAT(created_at, '%Y-%m')
GROUP BY user_id
ORDER BY user_id
) AS w ON w1.user_id = w.user_id AND w1.created_at = w.first_month
JOIN work AS w2 ON w1.user_id = w2.user_id AND w2.created_at = w.last_month
ORDER BY performance DESC
UPDATE
Even if I try to wrap it this way, the rankings are not right
SET #ranking := 0;
SELECT #ranking := #ranking + 1 as ranking, a.user_id, a.performance
FROM (
SELECT
w1.user_id,
IFNULL(ROUND(w2.realization / w1.realization), 4), 0) AS performance
FROM work w1
JOIN (
SELECT min(created_at) AS first_month, max(created_at) AS last_month, user_id
FROM work
WHERE (DATE_FOMAT(NOW(), '%Y-%m') = DATE_FORMAT(created_at, '%Y- %m')
GROUP BY user_id
ORDER BY user_id
) AS w ON w1.user_id = w.user_id AND w1.created_at = w.first_month
JOIN work AS w2 ON w1.user_id = w2.user_id AND w2.created_at = w.last_month
ORDER BY performance DESC
) AS a

Sql server errors in query

I am trying to collaborate 3 queries to perform arithmetic operation. The queries are shown in
(SELECT ITEM_ID,ISNULL(SUM(REC_GOOD_QTY),0)
FROM INVENTORY_ITEM
WHERE COMPANY_ID = 1
AND INVENTORY_ITEM.COMPANY_BRANCH_ID = 1
AND INVENTORY_ITEM.INV_ITEM_STATUS = 'Inward'
AND GRN_DATE < CAST('2017-01-10 00:00:00.0' AS DATETIME)
GROUP BY INVENTORY_ITEM.ITEM_ID) -
(SELECT ITEM_ID, SUM ( TOTAL_LITRE )
FROM STOCK_REQUISITION_ITEM B, STOCK_REQUISITION A
WHERE A.ID = B.REQUISITION_ID
AND A.COMPANY_ID = 1
AND A.REQ_FROM_BRANCH_ID = 1
AND A.REQUISITION_DATE < CAST('2017-01-10 00:00:00.0' AS DATETIME)
GROUP BY B.ITEM_ID) +
(SELECT ITEM_ID, SUM ( RETURN_QUANTITY )
FROM STOCK_RETURN_ITEM B, STOCK_RETURN A
WHERE A.ID = B.STOCK_RETURN_ID
AND A.COMPANY_ID = 1
AND A.COMPANY_BRANCH_ID = 1
AND A.RETURN_DATE <= CAST('2017-01-10 00:00:00.0' AS DATETIME)
GROUP BY B.ITEM_ID)
I am getting this error.
[Err] 42000 - [SQL Server]Incorrect syntax near '-'.
42000 - [SQL Server]Incorrect syntax near '+'
Not much to go on here for details. And we aren't actually sure if you are using mysql or sql server but pretty sure you are using sql server. I think you can accomplish what you are trying to do with something along these lines.
with Iventory as
(
SELECT i.ITEM_ID
, GoodQty = ISNULL(SUM(i.REC_GOOD_QTY), 0)
FROM INVENTORY_ITEM i
WHERE COMPANY_ID = 1
AND i.COMPANY_BRANCH_ID = 1
AND i.INV_ITEM_STATUS = 'Inward'
AND i.GRN_DATE < '2017-01-10'
GROUP BY i.ITEM_ID
)
, StockRequisition as
(
SELECT ITEM_ID
, TotalLitre = SUM(TOTAL_LITRE)
FROM STOCK_REQUISITION_ITEM B
JOIN STOCK_REQUISITION A ON A.ID = B.REQUISITION_ID
WHERE A.COMPANY_ID = 1
AND A.REQ_FROM_BRANCH_ID = 1
AND A.REQUISITION_DATE < '2017-01-10'
GROUP BY B.ITEM_ID
)
StockReturn as
(
SELECT ITEM_ID
, ReturnQuantity = SUM(RETURN_QUANTITY)
FROM STOCK_RETURN_ITEM B
JOIN STOCK_RETURN A ON A.ID = B.STOCK_RETURN_ID
WHERE A.COMPANY_ID = 1
AND A.COMPANY_BRANCH_ID = 1
AND A.RETURN_DATE <= '2017-01-10'
GROUP BY B.ITEM_ID
)
select i.ITEM_ID
, MyCalculation = i.GoodQty - isnull(Req.TotalLitre, 0) + isnull(sr.ReturnQuantity, 0)
from Inventory i
left join StockRequisition sr on sr.ITEM_ID = i.ITEM_ID
left join StockReturn Req on Req.ITEM_ID = i.ITEM_ID
In your queries you always returns two fields ITEM_ID and a numeric field.
To apply an arithmetical operation you must return one numeric field
The first query:
SELECT ITEM_ID,ISNULL(SUM(REC_GOOD_QTY),0)
becomes
SELECT ISNULL(SUM(REC_GOOD_QTY),0)
The second query:
SELECT ITEM_ID, SUM ( TOTAL_LITRE )
becomes
SELECT SUM ( TOTAL_LITRE )
The third query:
SELECT ITEM_ID, SUM ( RETURN_QUANTITY )
becomes
SELECT SUM ( RETURN_QUANTITY )
So the GROUP BY returns more than one row per query
UPDATE
i try to rewrite your query:
SELECT DISTINCT ii.item_id,
ISNULL(
(SELECT SUM(ii2.rec_good_qty)
FROM inventory_item ii2
WHERE ii2.item_id = ii.item_id
AND ii.company_id = 1
AND ii.company_branch_id = 1
AND ii.inv_item_status = 'Inward'
AND ii.grn_date < CAST('2017-01-10 00:00:00.0' AS DATETIME))
,0) -
ISNULL(
(SELECT SUM(total_litre)
FROM stock_requisition_item b
JOIN stock_requisition a
ON a.id = b.requisition_id
WHERE a.company_id = 1
AND a.req_from_branch_id = 1
AND a.requisition_date < CAST('2017-01-10 00:00:00.0' AS DATETIME))
,0) +
ISNULL(
(SELECT SUM(return_quantity)
FROM stock_return_item b
JOIN stock_return a
ON a.id = b.stock_return_id
WHERE a.company_id = 1
AND a.company_branch_id = 1
AND a.return_date <= CAST('2017-01-10 00:00:00.0' AS DATETIME))
,0) AS result
FROM inventory_item ii
WHERE ii.company_id = 1
AND ii.company_branch_id = 1
AND ii.inv_item_status = 'Inward'
AND ii.grn_date < CAST('2017-01-10 00:00:00.0' AS DATETIME)

SQL query adding where related to sub query

Trying to get a where statement on a sub query result. The below works as I want it to, with the exception of AND low_36 != NULL. I need this to stop results where the output of low_36 is NULL.
SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 ) AS low_36
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON v_v.code = offers.code
LEFT JOIN m_f_t ON v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON v.t_t_id = m_t_t.id
WHERE status = 1
AND low_36 != NULL
LIMIT 2 OFFSET 0
I know you can not use results from subqueries in the main where statement, but this is the closest I have come to the correct result. Thank you for any feedback
Quick way would be
SELECT *
FROM
(SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 ) AS low_36
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON v_v.code = offers.code
LEFT JOIN m_f_t ON v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON v.t_t_id = m_t_t.id
WHERE status = 1) a
WHERE low_36 IS NOT NULL
LIMIT 2 OFFSET 0
I suspect you want to exclude null values in the subquery itself, thereby avoiding nullifying your aggregate value. Try this:
SELECT offers.*,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 23 ) AS low_24,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 35 and price is not null) AS low_36,
(SELECT ROUND( MIN( price ) ,2) FROM o_prices WHERE o_id = offers.id AND months = 47 ) AS low_48
FROM offers
LEFT JOIN m_v ON m_v.code = offers.code
LEFT JOIN m_f_t ON m_v.f_t_id = m_f_t.id
LEFT JOIN m_t_t ON m_f_t.t_t_id = m_t_t.id
WHERE status = 1
LIMIT 2 OFFSET 0

Combining the result of two queries to one result SQL

I'm trying t create a compare, now i'm only able to make it as multiple result (two different result).
both of the result above is from two queries.
My first result query
SELECT
customercode,
CONVERT(DATE, TransDate) transdate,
SUM(TotalReceivable) AS total
FROM
SalesOrderHeader
WHERE
CustomerCode = 'K-MDMM4'
AND TransDate BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
CONVERT(DATE, TransDate), customercode
and my second query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
WHERE
b.active = 1
AND b.OutletCode LIKE 'K-MDMM4'
AND flag = 1
AND tanggal BETWEEN '2016-07-25' AND '2016-07-30'
GROUP BY
b.OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, ba, mpm, tf,
ul,remarks
ORDER BY
tanggal DESC
I want this result.
customercode | transdate | total_tbl1 | total_tbl2
K-MDMM4 2016-07-25 6004050 6004050
K-MDMM4 2016-07-26 6880340 6880340
K-MDMM4 2016-07-27 5745040 5745040
K-MDMM4 2016-07-28 7424820 7424820
I can't use jsfiddle :(. I don't know why. I can't create table via queries.
From now, I have this query
SELECT
b.OutletCode AS outlet,
tanggal,
(cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item, 0)) total,
SUM(d.TotalReceivable) AS total
FROM
transaksi a
LEFT JOIN
Outlet b ON a.Outlet = b.OutletCode
LEFT JOIN
area c ON b.areacode = c.areacode
LEFT JOIN
salesorderheader d ON CONVERT(DATE, a.tanggal) = CONVERT(DATE, d.transdate)
WHERE
b.active = 1
AND b.BrandCode LIKE '%%'
AND b.OutletCode LIKE '%%'
AND flag = 1
AND YEAR(tanggal) = '2016'
AND MONTH(tanggal) = '7'
AND outlet = 'K-MDMM4'
GROUP BY
OutletCode, tanggal, cash, cc, dc, flash,
piutang, reject, disc50, spesial_item, transdate, totalreceivable
ORDER BY
tanggal DESC
and the result so far from my desired result....
Combine both queries into a single join and select
SELECT tbl1.customercode,
CAST(tbl1.transdate AS DATE) AS transdate,
tbl1.total AS total_tbl1,
tbl2.total AS total_tbl2
FROM
(
-- Query 1
SELECT customercode,convert(date,TransDate) transdate,SUM(TotalReceivable) as total
FROM SalesOrderHeader
where CustomerCode = 'K-MDMM4'
and TransDate between '2016-07-25' and '2016-07-30'
group by convert(date,TransDate),customercode
) AS tbl1
INNER JOIN (
-- Query 2
select b.OutletCode as outlet,tanggal, (cash + cc + dc + flash + piutang + reject + disc50 +
isnull(spesial_item,0)) total From transaksi a
left join Outlet b on a.Outlet = b.OutletCode
left join area c on b.areacode = c.areacode
where b.active = 1 and b.OutletCode like 'K-MDMM4' and flag = 1 and tanggal
between '2016-07-25' and '2016-07-30'
group by b.OutletCode,tanggal,cash,cc,dc,flash,piutang,reject,disc50,spesial_item,ba,mpm,tf,ul,remarks
) AS tbl2 ON tbl2.outlet = tbl1.customercode AND CAST(tbl2.trnggal AS DATE) = CAST(tbl1.transdate AS DATE)
order by CAST(tbl1.transdate AS DATE) DESC;
I don't have a database installed on this PC but what you're looking for is:
SELECT val1, val2 FROM
(SELECT1_of_your_code AS table1) INNER JOIN
(SELECT2_of_your_code AS table2) ON
table1.x == table2.y