mysql -unable to make a sum of entries with same id - mysql

Hello everyone,
I'm just wondering if the below is possible.
Let's say i have this table
+---------+-------+
| item_id | price |
+---------+-------+
| 14 | 1500 |
| 74 | 1500 |
| 78 | 2500 |
+---------+-------+
And I'd like to select all item_id within this array (14,78,14)....
I thought I would be able to get the sum of all prices with this select:
mysql> select SUM(price) from items_db where item_id in (14,78,14);
+-------+
| price |
+-------+
| 4000 |
+-------+
1 row in set (0.00 sec)
But obviously it just skipped the price for the duplicate item_id.
So is there any way I could make this work?
Thanks in advance,
Alex

You can't. You need to split the values that you receive, insert them on a temporary table and then do a join with the table that contains the values you wish to sum.
Wouldn't it be easy to do the select and then postprocess it with whatever language are you comfortable with?

ok got it... if you list duplicates in the IN(...) it wont work.
At each row the database engine checks wether the rows matchs the IN (... ) list.
So it is no going to read a row twice in such a statement
One way to read a given row several times is through a join... If you want to do such a sum() through SQL you have to join an intermediate (temporary) table. something like:
create temporary table itemlist (item_id);
insert into itemlist values (14),(78),(14);
select sum(price) from items_db inner join itemlist using (item_id);
+------------+
| sum(price) |
+------------+
| 5500 |
+------------+

Related

How to pass the results from one mysql query to another mysql query?

I have a table where it has two columns, the first column has the stores names and the second column has the products names.
Each store has multiple products, and multiple stores can share the same product.
How can I Run READ only commands against this table so I get a distinct list of Stores and then query a list of products in each Store?
PS; I don't want to run any write operations in my sql db.
The end result should be something like:
----------------------
| Store | Product |
----------------------
| Store1| Product1 |
| Store1| Product2 |
| .. | .. |
| Store2| Product1 |
| Store2| Product2 |
| .. | .. |
| Store3| Product1 |
| Store3| Product2 |
| .. | .. |
----------------------
The question was already Answered below, Here is the query that worked:
SELECT DISTINCT product,store
FROM table_name
WHERE store in (
SELECT DISTINCT store
FROM table_name
);
I can't understand the nature of the result you want, but i imagine that you want a list of prodects per store. in that case you can use this requets
SELECT * FROM table_name WHERE store in (SELECT DISTINCT store from table_name);

Select count with value from different tables

I want to count all entries in one table grouped by the user id.
This is the query I used which works fine.
select uuid_mapping_id, count(*) from t_message group by uuid_mapping_id;
and these are the results:
+-----------------+----------+
| uuid_mapping_id | count(*) |
+-----------------+----------+
| 1 | 65 |
| 4 | 277 |
Now I would like to display the actual user name, instead of the ID.
To achieve this I would need the help of two different tables.
The table t_uuid_mapping which has two columns:
uid_mapping_id, which equals uuid_mapping_id in the other table.
And f_uuid which is also unique but completely different.
f_uuid can also be found in another table t_abook which also contains the names in the column f_name.
The result I am looking for should be:
+-----------------+----------+
| f_name | count(*) |
+-----------------+----------+
| admin | 65 |
| user1 | 277 |
I am new to the database topic and understand that this could be achieved by using JOIN in the query, but to be honest I did not completely understand this yet.
if I understand you correctly:
SELECT tm.f_name, COUNT(*) as count
FROM t_message tm
LEFT JOIN t_abook ta ON (tm.uuid_mapping_id = ta.uid_mapping_id)
GROUP BY tm.f_name

How to optimize search in list in SQL

I have to make a SQL query in Mysql to search a string list (for ex: 1,2,3) in a columns (for ex: list_id), which also have string value list (1,2,3).
For more detail, my_table is
+-----------+----------+
| id | list_id |
+-----------+----------+
| 1 | 29 |
| 2 | 30 |
| 3 | 31 |
| 4 | 4,5,6,7 |
| 5 | 8,9,10,11|
| 6 | 4,5,8,9 |
| 7 | 1,2,3,6 |
+-----------+----------+
The search value is 1,5,8 and I need get the rows have list_id have 1 or 5 or 8 in it's list. Therefore, the result wil be:
+-----------+----------+
| id | list_id |
+-----------+----------+
| 4 | 4,5,6,7 |
| 5 | 8,9,10,11|
| 6 | 4,5,8,9 |
| 7 | 1,2,3,6 |
+-----------+----------+
My query string is:
SELECT * FROM my_table
WHERE list_id LIKE '%,1,%'
OR list_id LIKE '1,%'
OR list_id LIKE '%,1'
OR list_id LIKE '%,5,%'
OR list_id LIKE '5,%'
OR list_id LIKE '%,5'
OR list_id LIKE '%,8,%'
OR list_id LIKE '8,%'
OR list_id LIKE '%,8'
It is match correct what I want. However, the length of query is in proportion to length of list.
Does REGEXP is better than LIKE in this circumstance?
Does anyone have experience to make another solution better?
You may try to concatenate commas to your field (or use SET in MySQL or make a better database structure - in which you join on tables in which the related data is stored).
SELECT * FROM yourtable WHERE CONCAT(',', fieldname, ',') like '%,1,%';
Yes, regular expressions will work for this. Here is what you can do:
SELECT * FROM junk
WHERE CONCAT(',', list_id, ',') REGEXP CONCAT(',(', REPLACE('1,3,8',',','|'), '),');
Results:
ID | LIST_ID
5 | 8,9,10,11
6 | 4,5,8,9
7 | 1,2,3,6
Please see SQL Fiddle demo here.
We turn the query list 1,3,8 into an alternating group 1|3|8. You might be able to do this in your application code to avoid using the REPLACE() function above.
UPDATE Apologies, I mistakenly used 1,3,8 as the query parameter instead of 1,5,8. But it should still work.
I am going to strongly suggest that you change the design of the database (I am assuming you have some control or influence over it).
You should make the id column non-unique and then the list_id column should contain a single value. You can then search as follows:
SELECT id WHERE list_id IN (1,5,8)
If it is a big table and there are a lot of list_id values, put an index on the list_id column.
If you need the output in a comma-separated list, then you will need to use an aggregating concatenation function with GROUP BY (e.g., GROUP_CONCAT() in MySQL).
If you cannot change the design of the schema, then use one of the other suggestions here.

Mysql - deleting duplicates

I have a table with a barcode column with a unique index. The data has been loaded with additional chars (-xx) at the end of each barcode to prevent duplicates, but there will be lots of duplicates once I strip off the suffix. Here is a sample of the data:
itemnumber barcode
17912 2-14
18082 2-1
21870 2-10
29219 2-8
Then I created two temporary tables, marty and manny, both with the itemnumber and the stripped down barcodes. So,both tables would contain
itemnumber barcode
17912 2
18082 2
21870 2
29219 2
etc
And the I tried to delete all but the first entry with barcode '2' in the marty table(and every other barcode). I hoped then to update the original table with the correct first entry and the users could fix up the duplicates themselves in time in the application.
So, this was my query to delete all but the first entry in the marty table for each barcode
DELETE FROM marty
WHERE itemnumber NOT IN
(SELECT MIN(itemnumber) FROM manny GROUP BY barcode)
There are 130,000 rows in marty and manny. The query took over 24 hours and then didn't finish properly. The connection to the server crashed and the query did not do all the updates.
Is there a better way to approach this that would not us the subquery, which i think is causing the delay? And the group by is probably slowing things down too with so many records.
Thanks
One more variant: this variant works without any temporary tables for deleting duplicates:
Delete m1
From Marty m1
join Marty m2
on m1.barcode = m2.barcode
and m1.itemnumber > m2.itemnumber
Here is a two-stage approach that avoids use of NOT IN. It also does not use the temporary table "manny". First, join "marty" to itself to pick out rows for which itemnumber != min(itemnumber). Use UPDATE to set barcode for these rows to NULL. A second pass with DELETE then removes all rows that were flagged in the first phase.
For this example, I split the barcode column of "marty" into two columns; it could be done with the table in its original format with some modification (need to split the column values on the fly).
select * from marty;
+------------+---------+---------+
| itemnumber | barcode | subcode |
+------------+---------+---------+
| 17912 | 2 | 14 |
| 18082 | 2 | 1 |
| 21870 | 2 | 10 |
| 29219 | 2 | 8 |
| 30133 | 3 | 5 |
| 30134 | 3 | 7 |
| 30139 | 3 | 9 |
| 30142 | 3 | 12 |
+------------+---------+---------+
8 rows in set (0.00 sec)
UPDATE
(marty m1
JOIN
(SELECT barcode,
MIN(itemnumber) AS itemnumber
FROM marty
GROUP BY barcode) m2
USING(barcode))
SET m1.barcode = NULL WHERE m1.itemnumber != m2.itemnumber;
mysql> select * from marty;
+------------+---------+---------+
| itemnumber | barcode | subcode |
+------------+---------+---------+
| 17912 | 2 | 14 |
| 18082 | NULL | 1 |
| 21870 | NULL | 10 |
| 29219 | NULL | 8 |
| 30133 | 3 | 5 |
| 30134 | NULL | 7 |
| 30139 | NULL | 9 |
| 30142 | NULL | 12 |
+------------+---------+---------+
8 rows in set (0.00 sec)
DELETE FROM marty WHERE barcode IS NULL;
MySQL is notoriously slow when using IN with very large sets. A scripted alternative:
Use a script to construct a long itemnumber = X OR itemnumber = y OR itemnumber = z clause (chunks size ~1000) and INSERT the matched rows (i.e. the ones that would not have been DELETEd in your previous query) into a new table, TRUNCATE the existing and load the contents of the new table back into the old with INSERT INTO marty SELECT * FROM marty_tmp.
You may want to lock the table or run in a transaction for the final TRUNCATE, INSERT.
edit:
Query SELECT MIN(itemnumber) FROM manny GROUP BY barcode from a script, store results in desiredItemNumbers array
Take batches of 1000 desiredItemNumbers and construct this query: INSERT INTO manny_tmp SELECT * FROM manny WHERE itemnumber = desiredItemNumbers[0] OR itemnumber = desiredItemNumbers[1] .... Rerun this query until you've exhausted the desiredItemNumbers array (n.b. the last query will probably have less than 1000 desiredItemNumbers).
You now have a table with the results that you would have been left with had you DELETEd the rest, so swap the contents of the marty and marty_tmp tables.
TRUNCATE marty
INSERT INTO marty SELECT * FROM marty_tmp
If you are creating temp tables anyway, how about building your table with an "INSERT INTO " or "CREATE TABLE .. AS ..." based on:
SELECT MIN(itemnumber) AS itemnumber, barcode
FROM marty
GROUP BY barcode

Combine count rows in MySQL

I've got a table in MySQL that looks roughly like:
value | count
-------------
Fred | 7
FRED | 1
Roger | 3
roger | 1
That is, it was created with string ops outside of MySQL, so the values are case- and trailing-whitespace-sensitive.
I want it to look like:
value | count
-------------
Fred | 8
Roger | 4
That is, managed by MySQL, with value a primary key. It's not important which one (of "Fred" or "FRED") is kept.
I know how to do this in code. I also know how to generate a list of problem values (with a self-join). But I'd like to come up with a SQL update/delete to migrate my table, and I can't think of anything.
If I knew that no pair of records had variants of one value, with the same count (like ("Fred",4) and ("FRED",4)), then I think I can do it with a self-join to copy the counts, and then an update to remove the zeros. But I have no such guarantee.
Is there something simple I'm missing, or is this one of those cases where you just write a short function outside of the database?
Thanks!
As an example of how to obtain the results you are looking for with a SQL query alone:
SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name;
If you make a new table to hold the correct values, you INSERT the above query to populate the new table as so:
INSERT INTO newtable (SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name);
Strangely, MySQL seems to do this for you. I just tested this in MySQL 5.1.47:
create table c (value varchar(10), count int);
insert into c values ('Fred',7), ('FRED',1), ('Roger',3), ('roger',1);
select * from c;
+-------+-------+
| value | count |
+-------+-------+
| Fred | 7 |
| FRED | 1 |
| Roger | 3 |
| roger | 1 |
+-------+-------+
select value, sum(count) from c group by value;
+-------+------------+
| value | sum(count) |
+-------+------------+
| Fred | 8 |
| Roger | 4 |
+-------+------------+
I was surprised to see MySQL transform the strings like that, and I'm not sure I can explain why it did that. I was expecting to have to get four distinct rows, and to have to use some string functions to map the values to a canonical form.