Why the sum value from mysql_fetch was double up? - mysql

I have an 2 database.
1 is game_jnship_user, 2 is game_jnship_equip and the data as below:
Here is game_jnship_user
+-----+-----------------+
| ID | uid |
+-----+-----------------+
| 1 | 50 |
+-----------------------+
Here is game_jnship_equip
+-----+------------+---------------+--------------+
| ID | uid | ebonus | etype |
+-----+------------+---------------+--------------+
| 1 | 50 | 100 | 1 |
| 2 | 50 | 10 | 1 |
| 3 | 50 | 120 | 2 |
+-------------------------------------------------+
And I query as below:
$_G['uid'] = '50';
$ushuxing = DB::query("SELECT sum(t2.ebonus) AS equipatk, sum(t3.ebonus) AS equipdef FROM ".DB::table('game_jnship_user')." t1 LEFT JOIN ".DB::table('game_jnship_equip')." t2 ON (t1.uid = t2.uid AND t2.etype = '1') LEFT JOIN ".DB::table('game_jnship_equip')." t3 ON (t1.uid = t3.uid AND t3.etype = '2') WHERE t1.uid = $_G[uid]");
$rushuxing = DB::fetch($ushuxing);
After that, my output data as below:
$rushuxing[equipatk] = 110;
$rushuxing[equipdef] = 240;
Why the $rushuxing[equipdef] output is 240 not 120?
Thank you.
Here is the raw MySQL query from the example above:
SELECT sum(t2.ebonus) AS equipatk, sum(t3.ebonus) AS equipdef
FROM game_jnship_user t1
LEFT JOIN game_jnship_equip t2
ON (t1.uid = t2.uid AND t2.etype = '1')
LEFT JOIN game_jnship_equip t3
ON (t1.uid = t3.uid AND t3.etype = '2')
WHERE t1.uid = '50'

The record having etype = 2 is matched with 2 records having etype = 1 in the LEFT JOIN operation, so you get 240 instead of 120.
You can use instead the following query that makes use of conditional aggregation:
SELECT SUM(CASE WHEN etype = 1 THEN ebonus ELSE 0 END) AS equipatk,
SUM(CASE WHEN etype = 2 THEN ebonus ELSE 0 END) AS equipdef
FROM game_jnship_equip
WHERE uid = 50
GROUP BY uid clause is not required since you are performing aggregation for a specific uid value.

Related

multiple sub query, count more sons but whit a condition

Hi! this work fine, but i need count more sons but whit a condition
select t1.*,(select count(*)
from tabl t2
where t2.tabl = t1.id) as sons
from tabl t1 where tabl.sons = ?;
I try this, but receive the following error...
SQL ERROR: Operand should contain 1 column(s)
select t1.*,(select count(*),(select count(*) from tbl1 t3 where t3.type = 3) as Johnny
from tabl t2
where t2.tabl = t1.id) as sons
from tabl t1 where tabl.sons = ?;
please, and thanks
Edit:
this do exactly i want, but i think is not the correct way to do
(i changed the names sorry, but it look better)
select m1.*,
(select count(*) from node m2 where m2.nodeid = m1.id) as child,
(select count(*) from node m3 where m3.type = 3 and m3.nodeid = m1.id) as del,
(select count(*) from node m3 where m3.type = 1 and m3.nodeid = m1.id) as edit,
(select count(*) from node m3 where m3.type = 4 and m3.nodeid = m1.id) as protect,
(select count(*) from node m3 where m3.type = 2 and m3.nodeid = m1.id) as move
from node m1 where nodeid = ?
+----+--------+------+-------+------+------+---------+------+
| id | nodeid | type | child | del | edit | protect | move |
+----+--------+------+-------+------+------+---------+------+
| 1 | null | 0 | 3 | 0 | 1 | 1 | 1 |
+----+--------+------+-------+------+------+---------+------+
+----+--------+------+-------+------+------+---------+------+
| id | nodeid | type | child | del | edit | protect | move |
+----+--------+------+-------+------+------+---------+------+
| 34 | 1 | 1 | 7 | 2 | 1 | 1 | 1 |
| 23 | 1 | 2 | 3 | 1 | 0 | 0 | 0 |
| 32 | 1 | 3 | 2 | 0 | 0 | 0 | 0 |
+----+--------+------+-------+------+------+---------+------+
basically how many children are and how many are of each type xd
MySQL 8 has got the window functions. Therefore, you can write your query in it like this:
SELECT t1.*, COUNT(*) OVER(PARTITION BY t1.id ORDER BY t1.id) AS sons,
COUNT(CASE WHEN t1.type = 3 THEN t1.type END) OVER (PARTITION BY t1.id ORDER BY t1.id) AS Johnny
FROM tabl t1
WHERE t1.sons = ?;
You cannot define multiple columns to one column.
(select count(*),(select count(*) from tbl1 t3 where t3.type = 3) as Johnny
from tabl t2 where t2.tabl = t1.id) as sons
sons : one column, count(*),,,Johnny : multiple column
Please change it to the following sql...
(select count(*) from tabl t2 where t2.tabl=t1.id), (select count(*) from tbl1 t3 where t3.type=3)
Is this what you are looking for?
select t.*,
count(*) over (partition by id) as sons,
sum(type = 3) over (partition by id) as johnny
from tabl t
having sons = ?;
MySQL extends the having clause so it can filter on table aliases in a non-aggregation query.

MySQL CASE ELSE not returning 0 in multi join select statement

I have a view like this:
VIEW `my_view` AS (
SELECT
t1.sku AS sku,
FORMAT(SUM((CASE
WHEN (t3.order_date > (CURDATE() - INTERVAL 42 DAY)) THEN t2.qty
ELSE 0
END)),
0) AS qty_sold,
FORMAT(SUM((CASE
WHEN (t3.order_status_id = 3) THEN t2.qty
ELSE 0
END)),
0) AS qty_ordered
FROM
inventory_products t1
JOIN inventory_sales t2 ON (t2.sku = t1.sku)
JOIN inventory_orders t3 ON (t3.id = t2.order_id)
where t1.sku=1001 or t1.sku=1002 or t1.sku=1010
GROUP BY t1.sku
)
The view works as expected, and returns correct results, except that when a sku doesn't exist on the inventory_sales table, the row for that sku doesn't return at all.
Note that the sku=1010 doesn't exist on the inventory_sales table, but it does exist on the inventory_products table.
for example:
SELECT * FROM my_view
WHERE sku=1001 OR sku=1002 OR sku=1010
returns this:
+-----------+--------------+------------+
| sku | qty_sold |qty_ordered |
+-----------+--------------+------------+
| 1001 | 2 | 2 |
+-----------+--------------+------------+
| 1002 | 3 | 3 |
+-----------+--------------+------------+
but I need it to return this:
+-----------+--------------+------------+
| sku | qty_sold |qty_ordered |
+-----------+--------------+------------+
| 1001 | 2 | 2 |
+-----------+--------------+------------+
| 1002 | 3 | 3 |
+-----------+--------------+------------+
| 1010 | 0 | 0 |
+-----------+--------------+------------+
What am I missing here? Any advice would be appreciated :)
I think you just need left join:
SELECT . . .
FROM inventory_products t1 LEFT JOIN
inventory_sales t2
ON t2.sku = t1.sku LEFT JOIN
inventory_orders t3
ON t3.id = t2.order_id
WHERE t1.sku IN (1001, 1002, 1010)
GROUP BY t1.sku
I think the ELSE 0 will turn the NULL into a 0 -- your desired result.

Show query result differently

I have this query:
SELECT pr_products.product AS PRODUCT, pr_varieties.variety AS VARIETY, pr_grades.GRADE, SUM(pf_harvest.quantity) AS QUANTITY
FROM pf_harvest
INNER JOIN pf_performance ON pf_performance.id = pf_harvest.id_performance
INNER JOIN pr_products ON pr_products.id = pf_harvest.id_product
INNER JOIN pr_varieties ON pr_varieties.id = pf_harvest.id_variety
INNER JOIN pr_grades ON pr_grades.id = pf_harvest.id_grade
WHERE pf_performance.status = 100
AND pf_harvest.id_tenant = 1
AND pf_harvest.date = '2017-03-22'
GROUP BY pf_harvest.id_product, pf_harvest.id_variety, pf_harvest.id_grade
ORDER BY pf_harvest.id_product, pr_varieties.variety, pf_harvest.id_grade;
Which shows me the following result:
-------------------------------------------------------------------
PRODUCT | VARIETY | GRADE | QUANTITY |
-------------------------------------------------------------------
ROSE | ROSEV1 | GRADE1 | 1000 |
-------------------------------------------------------------------
ROSE | ROSEV1 | GRADE2 | 5000 |
-------------------------------------------------------------------
ROSE | ROSEV2 | GRADE1 | 2000 |
-------------------------------------------------------------------
ROSE1 | ROSE1V1 | GRADE1 | 3500 |
-------------------------------------------------------------------
Is it possible to display the query result as follows?
-------------------------------------------------------------------
PRODUCT | VARIETY | GRADE1 | GRADE2 | TOTAL |
-------------------------------------------------------------------
ROSE | ROSEV1 | 1000 | 5000 | 6000 |
-------------------------------------------------------------------
ROSE | ROSEV2 | 2000 | 0 | 2000 |
-------------------------------------------------------------------
ROSE1 | ROSE1V1 | 3500 | 0 | 3500 |
-------------------------------------------------------------------
I tried to change the query but I could not and I would like to know if it is possible, I hope someone can help me.
UPDATED
NOTE: There may be more GRADES in the query result (GRADE1, GRADE2, GRADE3...).
Thanks!
Modify your current query by not grouping on the GRADE column, but instead pivot on that column. Then, use conditional aggregation to compute the GRADE1 and GRADE2 columns.
SELECT t3.product AS PRODUCT,
t4.variety AS VARIETY,
SUM(CASE WHEN t5.GRADE = 'GRADE1' THEN t1.quantity ELSE 0 END) AS GRADE1,
SUM(CASE WHEN t5.GRADE = 'GRADE2' THEN t1.quantity ELSE 0 END) AS GRADE2,
SUM(CASE WHEN t5.GRADE = 'GRADE3' THEN t1.quantity ELSE 0 END) AS GRADE3,
-- hopefully it is clear how to add more grades
SUM(t1.quantity) AS TOTAL
FROM pf_harvest t1
INNER JOIN pf_performance t2
ON t2.id = t1.id_performance
INNER JOIN pr_products t3
ON t3.id = pf_harvest.id_product
INNER JOIN pr_varieties t4
ON t4.id = t1.id_variety
INNER JOIN pr_grades t5
ON t5.id = t1.id_grade
WHERE t2.status = 100 AND
t1.id_tenant = 1 AND
t1.date = '2017-03-22'
GROUP BY t1.id_product,
t1.id_variety
ORDER BY t1.id_product,
t4.variety,
t1.id_grade;
try this
added this code
sum(case when pr_grades.Grade='Grade1' then pf_harvest.quantity else 0 end)) [Grade1],
sum(case when pr_grades.Grade='Grade2' then pf_harvest.quantity else 0 end)) [Grade2]
SELECT
pr_products.product AS PRODUCT,
pr_varieties.variety AS VARIETY,
sum(case when pr_grades.Grade='Grade1' then pf_harvest.quantity else 0 end)) [Grade1],
sum(case when pr_grades.Grade='Grade2' then pf_harvest.quantity else 0 end)) [Grade2],
SUM(pf_harvest.quantity) AS TOTAL
FROM pf_harvest
INNER JOIN pf_performance
ON pf_performance.id = pf_harvest.id_performance
INNER JOIN pr_products
ON pr_products.id = pf_harvest.id_product
INNER JOIN pr_varieties
ON pr_varieties.id = pf_harvest.id_variety
INNER JOIN pr_grades
ON pr_grades.id = pf_harvest.id_grade
WHERE pf_performance.status = 100
AND pf_harvest.id_tenant = 1
AND pf_harvest.date = '2017-03-22'
GROUP BY pf_harvest.id_product,
pf_harvest.id_variety
ORDER BY pf_harvest.id_product, pr_varieties.variety, pf_harvest.id_grade;

MySQL - Count only if the last associated_statut = 2

Alright, I have those columns on MySQL :
id
id_conv
associated_statut
The associated_statut is a number between 1 and 7.
What I want to do is to count only the id_conv if the LAST associated_statut for this id_conv is 2 for example.
Example :
-----------------------------------------------
| id | id_conv | associated_statut |
-----------------------------------------------
| 1 | 15 | 1 |
| 2 | 15 | 2 |
| 3 | 15 | 2 |
| 4 | 15 | 4 |
| 5 | 15 | 2 |
| 6 | 15 | 3 |
The id_conv would NOT be counted if I want the associated_statut = 2, because the last associated_statut for this id_conv is 3.
I already tried this query :
SELECT COUNT(DISTINCT id_conv) FROM MyTable WHERE associated_statut = 2
But this doesn't returns what I want.
Is there a way to do this in SQL ?
Thanks.
Maybe, this will work for you:
SELECT count(t1.id) FROM mytable t1
INNER JOIN (SELECT id_conv, MAX(id) id FROM foo GROUP BY id_conv) t2
ON t1.id = t2.id
WHERE t1.associated_statut = 2
SELECT COUNT(sub1.id_conv) FROM MyTable
INNER JOIN
(
SELECT DISTINCT id, FIRST(associated_statut ORDER BY id DESC)
group by id_conv
recent FROM MyTable
) sub1 ON sub1.id = MyTable.id
WHERE sub1.recent_associated_statut = 2
We can do same thing without sub query. It will take less time when you have more data.
SELECT count(t1.id) FROM
mytable t1
LEFT JOIN
mytable t2
ON t1.id_conv = t2.id_conv
AND t1.id < t2.id
WHERE t2.id IS NULL
AND t1.associated_statut = 2;

How can I join a table with itself with NULL values

I have this table (test):
+----+---------+-----+---+
| ID | Name | A | B |
+----+---------+-----+---+
| 1 | Steve | 200 | 0 |
| 2 | Steve | 200 | 1 |
| 5 | James | 90 | 0 |
| 4 | James | 50 | 1 |
| 3 | Warrick | 100 | 1 |
+----+---------+-----+---+
and this SQL query:
SELECT one.Name as Name, one.A as one_value, zero.A as zero_value
FROM test one LEFT JOIN test zero ON one.Name = zero.Name AND one.A <> zero.A
WHERE zero.B = 0 AND one.B = 1
which returns:
+-------+-----------+------------+
| Name | one_value | zero_value |
+-------+-----------+------------+
| James | 50 | 90 |
+-------+-----------+------------+
But what I want is when a record exists only with B = 1 that it is included in the response with a NULL value or something in the zero_value column, like this:
+---------+-----------+------------+
| Name | one_value | zero_value |
+---------+-----------+------------+
| James | 50 | 90 |
| Warrick | 100 | NULL |
+---------+-----------+------------+
How can I do this?
Edit:
I worked it out:
SELECT one.Name, one.A, zero.A
FROM test one LEFT JOIN test zero ON one.Name = zero.Name AND ( zero.B = 0 OR zero.B is NULL )
WHERE ( one.A <> zero.A OR zero.A is null )
Because of the left join the value of zero.B may be NULL, so you need to extend the WHERE condition:
WHERE one.B=1 AND (zero.B IS NULL OR zero.B = 0)
Update
You should also move the score condition down into WHERE:
WHERE one.B=1 AND (zero.B IS NULL OR zero.B = 0)
AND (zero.A IS NULL OR one.A <> zero.A)
How about this
select Name ,
(case when B= 0 Then A else null) as zero_value,
(case when B= 1 Then A else null) as one_value
from test
LEFT JOIN is a good thing here, this is what you want :
SELECT
one.Name
,one.A as one_value
, zero.A as zero_value
FROM test one
LEFT JOIN test zero
on one.Name = zero.Name
and zero.B = 0
where one.B = 1
Perhaps you want to handle when record exists only with B = 0 that it is included in the response with a NULL value in the one_value column in same time :
SELECT
test.Name
, one.A as one_value
, zero.A as zero_value
FROM
( SELECT Name
FROM test
GROUP BY Name) test
LEFT JOIN test one
on test.Name = one.Name
and one.B = 1
LEFT JOIN test zero
on test.Name = zero.Name
and zero.B = 0
Here is a demo for both queries :)
http://www.sqlfiddle.com/#!2/6332a/7/0
Try thiz query that give exact result for u
SELECT Test.nme,
one.A AS one_value,
zero.A AS zero_value
FROM(SELECT name AS nme FROM test WHERE name NOT in( SELECT one.Name FROM test one LEFT JOIN test zero ON (one.Name = zero.Name AND one.A=zero.A)
WHERE zero.B=0 AND one.B=1)GROUP BY name)Test
LEFT JOIN test one ON test.nme=one.Name AND one.B=1
LEFT JOIN test zero ON test.nme=zero.Name AND zero.B=0;