Combine count rows in MySQL - 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.

Related

MySQL: select all rows where just the name is distinct [duplicate]

This question already has answers here:
SQL select only rows with max value on a column [duplicate]
(27 answers)
Closed 4 years ago.
I'm currently trying to select unique entries in only the name column. I have tried using this query but it will not return prices that are the same as well. I've tried other variations with no success either.
SELECT DISTINCT name, price from table;
Here's the table I'm working with:
+----+-------------------+
| id | name | price |
+----+-----------+-------+
| 1 | Henry | 20 |
| 2 | Henry | 30 |
| 3 | Robert | 20 |
| 4 | Joshua | 10 |
| 5 | Alexander | 30 |
+----+-----------+-------+
The output that I'm seeking is:
+----+-------------------+
| id | name | price |
+----+-----------+-------+
| 1 | Henry | 20 |
| 3 | Robert | 20 |
| 4 | Joshua | 10 |
| 5 | Alexander | 30 |
+----+-----------+-------+
The desired output as you can tell only removed the duplicate name and none of the prices. Is there something I can add to my query above to only select unique entries in the name column? Any help is really appreciated as I have tried to find a solution on here, Google, DuckDuckGo, etc. with no luck.
From your sample data, this should work.
SELECT MIN(Id) AS Id, name, MIN(price) AS price
FROM table
GROUP BY name;
This is what GROUP BY is for:
SELECT * FROM `table` GROUP BY `name`
Usually people run into trouble because they will now get an arbitrarily-chosen row when more than one matches for a given name — you have to use aggregate functions to pick a specific one, e.g. "the one with the maximum price".
But in your case, since you don't seem to care which row is returned, this is perfect as-is.
So you want to select distinct list of rows AND then select that given entire row from the table? Try this query where temporary query is just a list of uniqueid then that row is linked back to the table.
Select n.*
From nameprices n
Join (Select MIN(id) as id
From nameprices
Group by name
Order By id) aTemp On (aTemp.id=n.id);
This is a common problem in SQL queries where we want to use that given fully row data but filter was using a distinct/groupby formula.

MySQL Query results

Table name : Students.
The Table i have:
mysql> SELECT * from Students;
+-----------+-------------+-------+
| Rollno | Name | Marks |
+-----------+-------------+-------+
| 251602122 | Sumit Tyagi | 70 |
| 251602121 | parveen | 90 |
+-----------+-------------+-------+
Following query returns the following result even 8 is not a attribute.
mysql> select 8 from Students;
+---+
| 8 |
+---+
| 8 |
| 8 |
+---+
Similarly
mysql> SELECT 'some_string' from Students;
+-------------+
| some_string |
+-------------+
| some_string |
| some_string |
I just want to know why this happens.
The query returns one line for every record in your table.
But you don't select data from those record. You just select the number 8 for each line. And this gets returned.
Select statement looks for column name in a table. You can make sure SQL look for a column name in a table by using TableName.ColumnName.
In the example you wrote, you are asking for a constant or hardcoded value 8/some_string to be returned from the table which is not the column name. So it will return the hardcoded or constant value you asked for, the number of times equal to number of rows in your table.
If you want to make sure it look for the column name, use the syntax I mentioned as TableName.ColumnName. You can also provide an alias for your table. So in the example above, if you use the syntax as
SELECT Students.8 from Students;
or
SELECT s.8 FROM Students s;
It will look for column name as 8 instead of constant or hardcoded value 8.
If I am not wrong, it is a best practice to use TableName.ColumnName or alias.ColumnName while writing queries as it checks for column name in that particular table.

Add user defined value to a column in an sql query

I have an SQL query:
select DISTINCT shortname_chn from dim_channel;
The query returns me data for example:
| shortname_chn (VARCHAR) |
|__________________________|
| MTV |
| National Geographic|
| Discovery |
| ARY News |
How can I manipulate the SQL query so that I can add an additional row to the returned rows.
Following is the result I wish to get after running some query:
| shortname_chn (VARCHAR) |
|__________________________|
| MTV |
| National Geographic|
| Discovery |
| ARY News |
| ALL |
Where the last row "ALL" is user defined, not present in the database.
In the above mentioned regard, I researched and came across this question : How to add a user defined column with a single value to a SQL query but it targets the problem of adding a whole new column.
select DISTINCT shortname_chn from dim_channel
UNION
SELECT 'ALL'
You can simply do something like this by UNIONing with a query that returns your fake row, e.g.:
SELECT DISTINCT
shortname_chn
FROM dim_channel
UNION ALL
SELECT 'ALL' AS shortname_chn

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 - COUNT before INSERT in one query

Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...