How to sum the duplicate values? - mysql

I have a MySQL table with rows containing duplicate values of text ('a' and 'c'):
+------+-----+
| text | num |
+------+-----+
| a | 10 |
| b | 10 |
| c | 10 |
| d | 10 |
| c | 5 |
| z | 10 |
| a | 6 |
+------+-----+
So, I want to update these rows summing the values of num. After that the table should look like this:
+------+-----+
| text | num |
+------+-----+
| a | 16 |
| b | 10 |
| c | 15 |
| d | 10 |
| z | 10 |
+------+-----+
UPD: Edited question.

Use the aggregate function SUM with a GROUP BY clause. Something like this:
SELECT `text`, SUM(num) AS num
FROM YourTableName
GROUP BY `text`;
SQL fiddle Demo
This will give you:
| TEXT | NUM |
--------------
| a | 16 |
| b | 10 |
| c | 15 |
| d | 10 |
| z | 10 |

You can create a temporary table to store the aggregated data temporarily into that and then update the original table from it.
Create a temporary table
select the aggregated data from the original
then delete all data in the original table
and then select the aggregated data from the temporary table into the original table.
Example SQL:
BEGIN;
CREATE TEMPORARY TABLE `table_name_tmp` LIKE `table_name`;
INSERT INTO `table_name_tmp` SELECT `text`, SUM(num) AS num FROM `table_name` GROUP BY 1;
DELETE FROM `table_name`;
INSERT INTO `table_name` SELECT * FROM `table_name_tmp`;
-- COMMIT;
I commented out the COMMIT command to avoid unwanted errors, please check the results before using it.

Related

Distinct order-number sequence for every customer

I have table of orders. Each customer (identified by the email field) has his own orders. I need to give a different sequence of order numbers for each customer. Here is example:
----------------------------
| email | number |
----------------------------
| test#com.com | 1 |
----------------------------
| example#com.com | 1 |
----------------------------
| test#com.com | 2 |
----------------------------
| test#com.com | 3 |
----------------------------
| client#aaa.com | 1 |
----------------------------
| example#com.com | 2 |
----------------------------
Is possible to do that in a simple way with mysql?
If you want update data in this table after an insert, first of all you need a primary key, a simple auto-increment column does the job.
After that you can try to elaborate various script to fill the number column, but as you can see from other answer, they are not so "simple way".
I suggest to assign the order number in the insert statement, obtaining the order number with this "simpler" query.
select coalesce(max(`number`), 0)+1
from orders
where email='test1#test.com'
If you want do everything in a single insert (better for performance and to avoid concurrency problems)
insert into orders (email, `number`, other_field)
select email, coalesce(max(`number`), 0) + 1 as number, 'note...' as other_field
from orders where email = 'test1#test.com';
To be more confident about not assign at the same customer two orders with the same number, I strongly suggest to add an unique constraint to the columns (email,number)
create a column order_number
SELECT #i:=1000;
UPDATE yourTable SET order_number = #i:=#i+1;
This will keep incrementing the column value in order_number column and will start right after 1000, you can change the value or even you can even use the primary key as the order number since it is unique all the time
I think one more need column for this type of out put.
Example
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
You can get this result:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
By running this query, which doesn't need any variable defined:
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
Hope that helps!
You can add number using SELECT statement without adding any columns in table orders.
try this:
SELECT email,
(CASE email
WHEN #email
THEN #rownumber := #rownumber + 1
ELSE #rownumber := 1 AND #email:= email END) as number
FROM orders
JOIN (SELECT #rownumber:=0, #email:='') AS t

mysql select with group by returning rows with a preference order

I have the following mysql query result:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 1 | hello1 | 2 |
| 1 | bonjour1 | 3 |
| 2 | ola2 | 1 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
What I want is a group_by query by id and that gives me for each id the title with a order of preference for lang field. Example:
Result for lang preference order 1, 2, 3:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 2 | ola2 | 1 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Result for lang preference order 3, 2, 1:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | bonjour1 | 3 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Thanks!
It is either not possible, or, not with in my SQL skills to execute that in one query. I always end up using a temporary template and two SQL commands for these problems:
(assuming that your table is called Table1 and the temporary table should be called tempTable)
SELECT Table1.id, Min(Table1.lang) AS Min_Of_lang INTO tempTable FROM Table1 GROUP BY Table1.id ORDER BY Table1.id;
SELECT Table1.* FROM tempTable INNER JOIN Table1 ON (tempTable.MinOflang = Table1.lang) AND (tempTable.id = Table1.id);
The first command creates a new table (that overrides the current table if it exists). The second command uses the first table to produce the desired result set.
To change from your first desired results table to the second, use Max instead of min in the first query.
Somebody else may well have a more elegant solution than mine. Also, an extra SQL statement could be added to delete the temporary table.
This is a feature that is not defined in MySQL. The displayed value in a non-aggregated column is undetermined. read more here (MySQL Documentation).
(Standard SQL doesn't allow to include non-aggregated columns when using GROUP BY, I guess this is one of the reasons).
From your description of the what you want to do, you should simple SELECT all rows with the lang you are looking for
SELECT * FROM your_table WHERE lang = 1

INSERT and SELECT sequence in MySQL

If I insert a value with an order by name like this.
+------------------+
| Table: example |
+------------------+
| Name | Value |
+---------+--------+
| A | 153 |
| B | 10 |
| C | 20 |
| D | 50 |
| E | 100 |
+---------+--------+
When I select the value with a query
select * from example
or
select * from example limit 2
without a where, order by or group by, is the order of the result defaulted to the insert order??
Thanks,

Inserting a series of numbers as rows in database

Is it possible to insert a series of rows that number off at the same time instead of individually inserting each?
So if I had a table with columns A and B and I wanted 50 rows with column A filled in from 1-50 is it possible to do that all on the same command without writing each number out, individually?
As you tagged this with Postgres:
insert into some_table (col_a, col_b)
select i, null
from generate_series(1,50) i;
More details about generate_series() in the manual:
http://www.postgresql.org/docs/current/static/functions-srf.html
You also tagged this with mysql.
If you have a utility table of integers (0-9, and simpler I think than a series of UNIONs) then you can emulate Postgres's clever behaviour as follows:
DROP TABLE IF EXISTS ints;
CREATE TABLE ints(i INT NOT NULL PRIMARY KEY);
INSERT INTO ints VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table(a INT NOT NULL PRIMARY KEY,b CHAR(1) NOT NULL);
INSERT INTO my_table (a,b) SELECT i2.i*10+i1.i+1 n,'x' FROM ints i1 JOIN ints i2 HAVING n <= 50;
SELECT * FROM my_table;
+----+---+
| a | b |
+----+---+
| 1 | x |
| 2 | x |
| 3 | x |
| 4 | x |
| 5 | x |
| 6 | x |
| 7 | x |
| 8 | x |
| .. |.. |
| .. |.. |
| .. |.. |
| .. |.. |
| 46 | x |
| 47 | x |
| 48 | x |
| 49 | x |
| 50 | x |
+----+---+

SELECT all value from table only once if they're duplicated

Lets say I have a table with the following rows/values:
+--------+----------+
| ID | adspot |
+--------+----------+
| 1 | A |
| 2 | B |
| 3 | A |
| 4 | B |
| 5 | C |
| 6 | A |
+--------+----------+
I need a way to select the values in adspot but only once if they're duplicated. So from this example I'd want to select A once and B once. The SQL result should look like this then:
+----------+
| adspot |
+----------+
| A |
| B |
| C |
+----------+
I'm using mySQL and PHP, in case anyone asks.
Thanks.
SELECT DISTINCT adspot FROM your_table; ( this may not perform well at all in large tables )
SELECT adspot FROM table GROUP BY adspot
see: http://www.tizag.com/mysqlTutorial/mysqlgroupby.php