yii: count value array depend on index group number - php

I have table from mysql like below:
id | name | grade | k1 | k2 | k3 | s1| s2 | s3| e1 | e1 | e3 |
1 | Aa | 5 | 1 | 0 | 5 | 3 | 2 | 1 | 0 | 6 | 1 |
2 | Bb | 1 | 1 | 3 | 5 | 3 | 5 | 3 | 4 | 6 | 1 |
3 | Cc | 2 | 1 | 4 | 2 | 2 | 2 | 4 | 0 | 6 | 1 |
4 | Dd | 4 | 1 | 3 | 5 | 3 | 3 | 1 | 0 | 6 | 1 |
5 | Ee | 3 | 1 | 5 | 2 | 1 | 0 | 5 | 0 | 6 | 1 |
6 | Ff | 2 | 1 | 3 | 1 | 3 | 4 | 2 | 0 | 6 | 1 |
7 | Gg | 5 | 1 | 1 | 5 | 5 | 2 | 1 | 0 | 6 | 1 |
Using FOR and FOREACH looping, i do able to show all row. But in final view/table i want to
SUM [k1,k2,k3], SUM[s1,s2,s3] and SUM[e1,e2,e3]
So it will place new colum as K, S and E in each row.
Here are my code:
for ($i = 0; $i < Evaluation::model()->count(); $i++) {
foreach (Yii::app()->db->createCommand()
->from('evaluation')
->queryAll() as $item) {
// Row-Column start here
// id | name | grade | K | S | E |
}
}
thanks.

I love the query builder. So here is one of the solution.
$result = Yii::app()->db->createCommand()->
select('id, name, grade, (k1+k2+k3) AS K, (s1+s2+s3) AS S, (e1+e2+e3) AS E')->
from(MyModel::model()->tableName())->
queryAll();
var_dump($result);

select k1+k2+k3, s1+s2+s3, e1+e2+e3 from t
and it is not yii question, it is about MySql
If you want to express it in Yii, you can
Yii:app()->createCommands()
->select('k1+k2+k3, s1+s2+s3, e1+e2+e3')
->from('t')
->queryAll();

Related

Mysql: How to swap data of one column between rows?

I already read Switch id numbers of two rows in MySql and Mysql: Swap data for different rows, yet I don't understand. Suppose a table colors that looks like this:
------------------------------------------
| id | box | pouch | color | value |
-----------------------------------------
| 1 | 1 | 1 | red | 30 |
| 2 | 1 | 1 | blue | 20 |
| 3 | 1 | 1 | green | 10 |
| 4 | 1 | 1 | yellow | 40 |
| 5 | 1 | 1 | purple | 20 |
| 6 | 1 | 1 | black | 50 |
| 7 | 1 | 2 | red | 30 |
| 8 | 1 | 2 | blue | 20 |
| 9 | 1 | 2 | green | 10 |
| 10 | 1 | 2 | yellow | 40 |
| 11 | 1 | 2 | purple | 20 |
| 12 | 1 | 2 | black | 50 |
| 13 | 2 | 1 | red | 35 |
| 14 | 2 | 1 | blue | 25 |
| 15 | 2 | 1 | green | 15 |
| 16 | 2 | 1 | yellow | 45 |
| 17 | 2 | 1 | purple | 25 |
| 18 | 2 | 1 | black | 55 |
| 19 | 2 | 2 | red | 35 |
| 20 | 2 | 2 | blue | 25 |
| 21 | 2 | 2 | green | 15 |
| 22 | 2 | 2 | yellow | 45 |
| 23 | 2 | 2 | purple | 25 |
| 24 | 2 | 2 | black | 55 |
------------------------------------------
How can I swap the "value" of a row with another, leaving the "id", "box", "pouch", and "color" intact?
Notes:
1. I need to swap the value of box='1' with box='2'
2. The number of rows are dynamic
Example:
SWAP ROWS OF VALUE WITH BOX='1' WITH ROWS OF VALUE WITH BOX='2'
Result:
------------------------------------------
| id | box | pouch | color | value |
-----------------------------------------
| 1 | 1 | 1 | red | 35 |
| 2 | 1 | 1 | blue | 25 |
| 3 | 1 | 1 | green | 15 |
| 4 | 1 | 1 | yellow | 45 |
| 5 | 1 | 1 | purple | 25 |
| 6 | 1 | 1 | black | 55 |
| 7 | 1 | 2 | red | 35 |
| 8 | 1 | 2 | blue | 25 |
| 9 | 1 | 2 | green | 15 |
| 10 | 1 | 2 | yellow | 45 |
| 11 | 1 | 2 | purple | 25 |
| 12 | 1 | 2 | black | 55 |
| 13 | 2 | 1 | red | 30 |
| 14 | 2 | 1 | blue | 20 |
| 15 | 2 | 1 | green | 10 |
| 16 | 2 | 1 | yellow | 40 |
| 17 | 2 | 1 | purple | 20 |
| 18 | 2 | 1 | black | 50 |
| 19 | 2 | 2 | red | 30 |
| 20 | 2 | 2 | blue | 20 |
| 21 | 2 | 2 | green | 10 |
| 22 | 2 | 2 | yellow | 40 |
| 23 | 2 | 2 | purple | 20 |
| 24 | 2 | 2 | black | 50 |
------------------------------------------
Anyone got some ideas? Thanks
Create a table that holds all values you want to swap.
create table tmp_t as select * from t;
Then update your table twice:
update t t1
inner join tmp_t t2 on t1.color = t2.color
and t1.pouch = t2.pouch
and t1.box = 1 and t2.box = 2
set t1.value = t2.value;
update t t1
inner join tmp_t t2 on t1.color = t2.color
and t1.pouch = t2.pouch
and t1.box = 2 and t2.box = 1
set t1.value = t2.value;
And that's it. See it working live in an sqlfiddle.
To do the swap, try resetting one of them to a temporary value. You need to do that, otherwise the second update will affect the first one.
UPDATE mytable SET box = -1 WHERE box = 1; -- Set box 1 to a temporary value
UPDATE mytable SET box = 1 WHERE box = 2; -- Set box 2 to box 1
UPDATE mytable SET box = 2 WHERE box = -1; -- Set box 1 to box 2
I've assumed it is not possible to have a negative box number. If -1 is permissible, use something else, such as null.
For extra safety, wrap the above in a transaction, so if anything goes wrong, you can rollback.

Concatenate and Count the multiple rows in single rows in mysql

I want to concatenate and count data of the same column, so I can concatenate but I can not count the repeated data.
Here's my table of data:
| ID | bills | class |
|-----|-------|-------|
| 1 | 0.5 | 2 |
| 2 | 1 | 1 |
| 3 | 0.5 | 2 |
| 5 | 1 | 3 |
| 6 | 0 | 2 |
| 7 | 0.5 | 1 |
| 8 | 1 | 2 |
| 9 | 1 | 3 |
| 10 | 0.5 | 1 |
| 11 | 0 | 2 |
| 12 | 1 | 1 |
| 13 | 0 | 3 |
| 14 | 1 | 2 |
| 15 | 0 | 1 |
| 16 | 0 | 1 |
| 17 | 0.5 | 3 |
| 18 | 0 | 3 |
| 13 | 0.5 | 3 |
Here's my sql query I'm using to concatenate data:
SELECT class AS lesson,
GROUP_CONCAT( bills ORDER BY bills ) AS bills
FROM tb_presence
GROUP BY class;
Here's my result below:
| class | bills |
|-------|------------------|
| 1 | 1,0.5,0.5,1,0,0 |
| 2 | 0.5,0,1,0,1 |
| 3 | 1,1,0,0.5,0,0.5 |
Now I would like to count the data that are equal, but continue with the same concatenation.
I want to "count" the data with the same values ​​and display concatenated (column observation and only to help understanding)
| class | bills | observation |
|-------|-------|-----------------------------|
| 1 | 2,2,2 | (2=0+0) (2=0.5+0.5) (2=1+1) |
| 2 | 2,1,2 | (2=0+0) (1=0.5) (2=1+1) |
| 3 | 2,2,2 | (2=0+0) (2=0.5+0.5) (2=1+1) |
Is this really possible?
Here is a solution (thanks to #wchiquito for the sqlfiddle) See http://sqlfiddle.com/#!2/2d2c8/1
As you can see it cannot dynamically determine the bills' values and count them. But there is a count per bill value that you want.
SELECT class AS lesson,
GROUP_CONCAT( bills ORDER BY bills ) AS bills
,SUM(IF(bills=0,1,0)) AS Count0
,SUM(IF(bills=0.5,1,0)) AS Count05
,SUM(IF(bills=1,1,0)) AS Count1
,COUNT(*) AS totalRecords
,COUNT(*)
- SUM(IF(bills=0,1,0))
- SUM(IF(bills=0.5,1,0))
- SUM(IF(bills=1,1,0))
AS Missing
FROM tb_presence GROUP BY class;
I added an extra record to show how the 'missing' column could show if you were not taking all values into consideration.
Results
| LESSON | BILLS | COUNT0 | COUNT05 | COUNT1 | TOTALRECORDS | MISSING |
|--------|-----------------------------------------|--------|---------|--------|--------------|---------|
| 1 | 0.00,0.00,0.50,0.50,1.00,1.00,1.00,4.00 | 2 | 2 | 3 | 8 | 1 |
| 2 | 0.00,0.00,0.50,0.50,1.00,1.00 | 2 | 2 | 2 | 6 | 0 |
| 3 | 0.00,0.00,0.50,0.50,1.00,1.00 | 2 | 2 | 2 | 6 | 0 |

How to display dynamic mysql vertical data to horizontal using php

I want to display dynamic mysql vertical data to horizontal in html table using PHP. And my table is like
mysql> select * from role_perm;
-------------------------------------------
| id | userID | roleID | permID | value |
--------------- ---------------------------
| 1 | 2 | 1 | 1 | 1 |
|------------------------------------------
| 2 | 2 | 1 | 2 | 0 |
|------------------------------------------
| 3 | 2 | 1 | 3 | 0 |
|------------------------------------------
| 4 | 2 | 2 | 4 | 0 |
-------------------------------------------
| 5 | 2 | 2 | 1 | 1 |
|------------------------------------------
| 6 | 2 | 2 | 2 | 1 |
|------------------------------------------
| 7 | 2 | 2 | 3 | 0 |
|------------------------------------------
| 8 | 2 | 2 | 4 | 1 |
-------------------------------------------
| 9 | 5 | 1 | 1 | 1 |
|------------------------------------------
| 10 | 5 | 1 | 2 | 0 |
|------------------------------------------
| 11 | 5 | 1 | 3 | 0 |
|------------------------------------------
| 12 | 5 | 1 | 4 | 0 |
-------------------------------------------
and so on...
and i want to display in html table like
----------------------------
| role | permissions |
----------------------------
| 1 | 1 | 2 | 3 | 4 |
----------------------------
| 2 | 1 | 2 | 3 | 4 |
----------------------------
| 3 | 1 | 2 | 3 | 4 |
-----------------------------
| 4 | 1 | 2 | 3 | 4 |
----------------------------
could you pls help me. Thank you in advance.
Try this:
SELECT
roleID AS role,
GROUP_CONCAT(DISTINCT permID ORDER BY permID ASC SEPARATOR '|') AS permissions
FROM role_perm
GROUP BY roleID
ORDER BY roleID
I suppose you could do this with a nifty MySQL query as well (which would supposedly be better for performance), but since I'm not that good at SQL, here's the PHP solution:
$arrRoles = array();
while ($row = mysql_fetch_assoc($result)) {
if (!isset($arrRoles[$row['roleID']])) {
$arrRoles[$row['roleID']] = array();
}
$arrRoles[$row['roleID']][$row['permID']] = $row['value'];
}
var_dump($arrRoles);

Selecting Total value of items from 2 tables and update value of another TABLE (COMPLICATED QUERY)

My case is that I want to compute a player atk power to be used on a battle module that i made, but just wondering i have actually 2 options:
Calculate Damage Dealt from the server.(my CURRENT OPTIONS)
use PHP to calculate DAMAGE DEALT and UPDATE server DATABASE values.
pass 2 of the chara id and just calculate all in the QUERY and UPDATE all(is this possible).
Question: Can I do it in a query?(option B)
my current set-up:
1 character has 4 items and i compute the characters atk by adding all 4 of the item atk and the chara base atk in the client side. (which i think is prone to security holes)
and then update the values in the server side.
Here is my tables:
chara:
+----------+------------+----------------+-------------+------------+----------+----------+----------+-----------+-----------+
| chara_id | chara_name | chara_class_id | chara_level | chara_gold | chara_hp | chara_mp | chara_xp | chara_atk | chara_def |
+----------+------------+----------------+-------------+------------+----------+----------+----------+-----------+-----------+
| 1 | LawrenceX | 1 | 5 | 230 | -175 | 1000 | 0 | 7 | 3 |
| 3 | Viscocent | 2 | 2 | 96 | -206 | 1100 | 1700 | 5 | 5 |
| 4 | Piatos | 1 | 1 | 120 | -60 | 1000 | 0 | 7 | 3 |
| 5 | Hello | 1 | 1 | 300 | -50 | 1000 | 200 | 2 | 8 |
| 6 | Sample | 3 | 2 | 251 | -85 | 900 | 0 | 9 | 1 |
| 8 | Sampuro | 2 | 1 | 170 | 895 | 1100 | 700 | 5 | 5 |
| 12 | fail | 2 | 3 | 481 | 1100 | 1300 | 0 | 21 | 9 |
| 13 | new | 1 | 1 | 1000 | -80 | 1000 | 0 | 5 | 5 |
+----------+------------+----------------+-------------+------------+----------+----------+----------+-----------+-----------+
items:
+---------+-----------------+-----------+----------+----------+----------+---------------------------------+-------------------------------------------------+------------+
| 0 | None | 0 | 0 | 0 | 0 | pics/none.png | | 400 |
| 1 | Axe | 1 | 220 | 10 | 0 | pics/weapons/axe.png | Another lumberjack axe is another man's weapon. | 200 |
| 2 | Wooden Sword | 1 | 70 | 0 | 0 | pics/weapons/wooden-sword.png | A wooden sword, 99% made from wood | 225 |
| 3 | Dagger | 1 | 60 | 5 | 0 | pics/weapons/dagger.png | A Dagger, Cheap and Sharp | 55 |
| 4 | Bow | 1 | 120 | 1 | 0 | pics/weapons/bow.png | The basics and simplest of all bows. | 120 |
| 5 | Helmet | 4 | 0 | 50 | 0 | pics/headgears/helmet.png | iron helmet - made from an iron pot scraps. | 155 |
| 6 | Tunic | 2 | 10 | 10 | 0 | pics/armors/tunic.png | A peasants tunic. | 50 |
| 7 | Armour | 2 | 0 | 75 | 0 | pics/armors/armour.png | | 150 |
| 8 | Necklace | 3 | 25 | 15 | 0 | pics/accessories/necklace.png | | 199 |
| 9 | Studded Leather | 2 | 25 | 60 | 0 | pics/armors/studded-leather.png | | 240 |
+---------+-----------------+-----------+----------+----------+----------+---------------------------------+-------------------------------------------------+------------+
equipment:
+----------+----------+-----------+-------------+----------+---------+
| equip_id | chara_id | weapon_id | headgear_id | armor_id | ring_id |
+----------+----------+-----------+-------------+----------+---------+
| 3 | 1 | 14 | 5 | 6 | 8 |
| 5 | 3 | 4 | 5 | 6 | 8 |
| 6 | 4 | 11 | 5 | 7 | 8 |
| 7 | 5 | 12 | 5 | 6 | 8 |
| 8 | 6 | 3 | 16 | 7 | 8 |
| 10 | 8 | 15 | 5 | 7 | 8 |
| 13 | 12 | 14 | 5 | 6 | 17 |
| 40 | 13 | 3 | 5 | 7 | 8 |
+----------+----------+-----------+-------------+----------+---------+
table relationships:
1 chara = 1 equipment
1 weapon_id, armor_id, ring_id, headgear_id = 1 item (total of 4 items, headgear_id = 1 item).
I CAN GET THE EQUIPMENTS OF A CHARACTER BY USING THIS QUERY(KUDOS #JC):
SELECT i1.item_atk weapon_atk,i1.item_def weapon_def,
i2.item_atk headgear_atk,
i2.item_def headgear_def,
i3.item_atk armor_atk,
i3.item_def armor_def,
i4.item_atk ring_atk,
i4.item_def ring_def
FROM equipment e LEFT JOIN
item i1 ON e.weapon_id = i1.item_id LEFT JOIN
item i2 ON e.headgear_id = i2.item_id LEFT JOIN
item i3 ON e.armor_id = i3.item_id LEFT JOIN
item i4 ON e.ring_id = i4.item_id
WHERE e.chara_id = 1
RESULTS:
+------------+------------+--------------+--------------+-----------+-----------+----------+----------+
| weapon_atk | weapon_def | headgear_atk | headgear_def | armor_atk | armor_def | ring_atk | ring_def |
+------------+------------+--------------+--------------+-----------+-----------+----------+----------+
| 275 | 25 | 0 | 50 | 10 | 10 | 25 | 15 |
+------------+------------+--------------+--------------+-----------+-----------+----------+----------+
now i want to total the atk and def of that character equipment and return it in that query
expected results:
+------------+------------+
| total_atk | total_def |
+------------+------------+
| 310 | 100 |
+------------+------------+
this is the simplest way that I can think of.
SELECT IFNULL(W.item_atk, 0) + IFNULL(H.item_atk, 0) + IFNULL(A.item_atk, 0) + IFNULL(R.item_atk, 0) AS total_atk
, IFNULL(W.item_def, 0) + IFNULL(H.item_def, 0) + IFNULL(A.item_def, 0) + IFNULL(R.item_def, 0) AS total_def
FROM equipment E
LEFT JOIN item W ON W.item_id = E.weapon_id
LEFT JOIN item H ON H.item_id = E.headgear_id
LEFT JOIN item A ON A.item_id = E.armor_id
LEFT JOIN item R ON R.item_id = E.ring_id
WHERE E.chara_id = 1
I have renamed the aliases of tables to track them easily. And I used IFNULL in case the character has no particular equipment.
==================================================================================
Dude, I just made another query, I think this is faster than the one above. Though, I haven't tested them.
SELECT SUM(IFNULL(I.item_atk, 0)) AS total_atk
, SUM(IFNULL(I.item_def, 0)) AS total_def
FROM equipment E
LEFT JOIN item I ON I.item_id = E.weapon_id
OR I.item_id = E.headgear_id
OR I.item_id = E.armor_id
OR I.item_id = E.ring_id
WHERE E.chara_id = 1
GROUP BY E.chara_id

swapping values in different tables if the data exist then value + 1 if data = 0 then delete

i have this table called bag:
+--------+----------+---------+----------+
| bag_id | chara_id | item_id | item_qty |
+--------+----------+---------+----------+
| 1 | 1 | 2 | 26 |
| 2 | 1 | 1 | 56 |
| 3 | 3 | 1 | 4 |
| 6 | 3 | 4 | 3 |
| 7 | 4 | 4 | 3 |
| 8 | 5 | 4 | 3 |
| 9 | 6 | 4 | 2 |
| 10 | 1 | 5 | 1 |
| 14 | 1 | 8 | 1 |
| 15 | 1 | 6 | 2 |
| 18 | 1 | 4 | 4 |
| 19 | 1 | 3 | 2 |
| 29 | 8 | 1 | 1 |
| 30 | 8 | 7 | 2 |
| 33 | 6 | 2 | 1 |
| 34 | 3 | 5 | 1 |
| 35 | 3 | 8 | 3 |
| 37 | 4 | 3 | 1 |
| 45 | 3 | 3 | 14 |
| 46 | 8 | 2 | 2 |
| 60 | 8 | 5 | 2 |
| 61 | 3 | 2 | 10 |
| 74 | 12 | 2 | 1 |
| 97 | 12 | 5 | 1 |
| 103 | 3 | 6 | 1 |
+--------+----------+---------+----------+
and have this table called equipment:
+----------+----------+-----------+-------------+----------+---------+
| equip_id | chara_id | weapon_id | headgear_id | armor_id | ring_id |
+----------+----------+-----------+-------------+----------+---------+
| 3 | 1 | 4 | 5 | 9 | 8 |
| 5 | 3 | 2 | 5 | 3 | 8 |
| 6 | 4 | 7 | 5 | 3 | 8 |
| 7 | 5 | 4 | 5 | 3 | 8 |
| 8 | 6 | 3 | 5 | 2 | 8 |
| 10 | 8 | 3 | 5 | 2 | 8 |
| 11 | 3 | 2 | 5 | 0 | 8 |
| 12 | 3 | 2 | 5 | 0 | 8 |
| 13 | 12 | 2 | 0 | 0 | 0 |
| 14 | 5 | 4 | 0 | 0 | 0 |
| 15 | 1 | 1 | 0 | 0 | 0 |
| 16 | 1 | 0 | 0 | 6 | 0 |
| 17 | 4 | 4 | 0 | 0 | 0 |
| 18 | 8 | 2 | 0 | 0 | 0 |
| 19 | 3 | 2 | 5 | 0 | 8 |
+----------+----------+-----------+-------------+----------+---------+
scenario:
player equips an item from the bag to equipment:
#unequipping:
1. if equipment id to be unequipped exist in the bag then that bag item = item + 1
else
insert that item to the bag
#equipping:
1. bag item = bag item - 1 where item_id = equipped item_id
else if bag item = 0 then delete it.
basically i want to swap the item's from the equipment to the bag table,
though the twist is the quantity, wherein if that item to be swapped is already existing in the bag table then + 1 to the quantity and if the item from the bag table is = 1 then remove that item from the table and equip that item to the equipment table.
please pm me if you couldn’t understand my situation, its driving me nuts!
this is my current code(if it helps a little):
$fieldnames = array(1=>'weapon', 'armor', 'ring', 'headgear');
if (isset($fieldnames[$equip->item_type])) {
$field = $fieldnames[$equip->item_type].'_id';
$sql_unequip = "INSERT INTO bag(item_id, chara_id, item_qty)VALUES(:item_id, :chara_id, 1) ON DUPLICATE KEY UPDATE item_qty = item_qty + 1";
$sql_equip = "UPDATE equipment SET $field = :item_id WHERE chara_id = :chara_id";
$sql_unequip2 = "DELETE FROM bag WHERE item_id = :item_id AND chara_id = :chara_id AND item_qty = 0";
}

Categories