sql group by value within substring of char(255) field - mysql

I have a column called image_small for a table images which will have information like this:
image_small
/images/menu_items/148/5a13140f8ef4503f024d06231037c69e_medium.jpg
/images/menu_items/152/5a14444444444444424d06231037c69e_medium.jpg
...
I'd like to select out a the count of unique values for the menu item value (148) above (assume 148-400) on Mysql 5.1 using innodb so that output would be like:
val count
148 5
101 4
152 1
The integer values (148,101,152) don't exist in a column and would rather not loop through.
Any ideas on how to do this? Would seem like would need to create a notion of a variable for the '148' and then a group by but a little clueless.
thx

I'm supposing that all your paths have the same format.
select
substring_index(substring_index(str,'/',4),'/',-1) as val,
count(*) as `count`
from table
group by val
It seems to work but I'm afraid about performance on large tables. Do some tests.
Could you add a field with this value? I think it would be better.

Related

SQL query for fetching rows with their id mentioned in a column of that same row

I am trying to get those rows whose Id's I have described in a column of that same table . Here's the data:
id layer sublayer
1 A 2, 3, 4
2 B 5
3 C NULL
4 D NULL
5 E NULL
Here's what I am trying to do.
For layer A ,I want to fetch B,C,D whose id's are described in the column sublayer . Here id is the primary key.Is it possible to read individual values from a column separated with special characters ?
Using Find_In_set function for set datatypes in conjunction with group_concat (cross join may not be needed but I like it for the fact it calculates the set once instead of for each row..)
I'm using group concat to bring all the rows into one large data set so we can simply check for the existence of the ID. However, I'm not sure how well group_concat will work with a set datatype already having a , separated values...
On a large data set I would be concerned about performance. Your best bet long term is to normalize the data. But if that's not an option...
Working SQL Fiddle:
SELECT *
FROM layer
CROSS JOIN (SELECT group_Concat(sublayer separator ',') v FROM layer) myset
WHERE FIND_IN_SET(ID, myset.v) > 0;
try this way
SELECT *
FROM layer
WHERE FIND_IN_SET(ID,(
select sublayer from table where layer='A'))>1

SUMing Dynamically Created Columns in MySQL

UPDATE: Not sure if what I'm trying to achieve is possible but thanks for all the help - is it appropriate to request this be deleted? I don't want the contributors to lose the upvotes I've given them for their help.
UPDATE: Just to be clear, when I say columns are created 'dynamically' I mean without developer input so they are an unknown. They are still properly defined columns in a standard database table - I just don't know the names of all of them. :-D
I have a table with columns created dynamically (very rarely but I'm trying to make this as robust as possible). I need to output the SUM of these columns, ordered by highest first but obviously also need the column names in the first row (as otherwise the data is useless). I've retrieved the columns using the information_schema.columns method in to PHP and thought I'd iterate through the columns performing a SUM but if I do that, they are not ordered numerically.
This can be built in to an SP (I'm assuming it will have to be done in an SP due to complexity). I believe I probably need to involve 'PIVOT' somewhere but that is the limit of my knowledge!
So to SUMmarise (see what I did there :-D )
I have a table definition with columns like this:
volunteerID INT
yearAdded DATETIME
willySize111to120 INT
willySize121to130 INT
willySize131to140 INT
willySize141to150 INT
I'd like to return a dataset like this in a query where I can specify the year:
sizeBracket count
willySize111to120 98
willySize121to130 76
willySize131to140 54
willySize141to150 23
Every time I think I've figured out a way to do it, I hit another wall.
Thanks for any help or pointers!
Bob
Assuming that your original table has a 1 in the correct bracket for each volunteer and a 0 in all other brackets:
SELECT bracket.sizeBracket, COUNT(*) count
FROM (
SELECT CASE
WHEN willySize111to120 THEN 'willySize111to120'
WHEN willySize121to130 THEN 'willySize121to130'
WHEN willySize131to140 THEN 'willySize131to140'
WHEN willySize141to150 THEN 'willySize141to150'
END CASE sizeBracket
FROM ... -- < Table Name
WHERE ... -- < Date Selection Logic
) bracket
GROUP BY sizeBracket
ORDER BY count DESC
UPDATE
Based on a raw data table willySize with columns
volunteerID INT
yearAdded DATETIME
willySize INT
You could run the following query
SELECT
CONCAT(
'willySize',
ROUND(willySize-6,-1)+1,
'to',
ROUND(willySize+4,-1)
) sizeBracket,
COUNT(*) count
FROM willySize
GROUP BY sizeBracket
ORDER BY count DESC

it is possible to "group by" without losing the original rows?

i have a query like this:
ID | name | commentsCount
1 | mysql for dummies | 33
2 | mysql beginners guide | 22
SELECT
...,
commentsCount // will return 33 for first row, 22 for second one
FROM
mycontents
WHERE
name LIKE "%mysql%"
also i want to know the total of comments, of all rows:
SELECT
...,
SUM(commentsCount) AS commentsCountAggregate // should return 55
FROM
mycontents
WHERE
name LIKE "%mysql%"
but this one obviously returns a single row with the total.
now i want to merge these two queries in one single only,
because my actual query is very heavy to execute (it uses boolean full text search, substring offset search, and sadly lot more), then i don't want to execute it twice
is there a way to get the total of comments without making the SELECT twice?
!! custom functions are welcome !!
also variable usage is welcome, i never used them...
You can cache the intermediate result to a temporary table, and then do the sum over this table
One obvious solution is storing intermediate results withing another 'temporary' table, and than perform aggregation in the second step.
Another solution is preparing a lookup table containing sums you need (but there obviously needs to be some grouping ID, I call it MASTER_ID), like that:
CREATE TABLE comm_lkp AS
SELECT MASTER_ID, SUM(commentsCount) as cnt
FROM mycontents
GROUP BY MASTER_ID
Also create an index on that table on column MASTER_ID. Later, you can modify your query like that:
SELECT
...,
commentsCount,
cnt as commentsSum
FROM
mycontents as a
JOIN comm_lkp as b ON (a.MASTER_ID=b.MASTER_ID)
WHERE
name LIKE "%mysql%"
It also shouldn't touch your performance as long as lookup table will be relatively small.
A GROUP BY on one of the ID fields might do the trick. This will then give you the SUM(commentsCount) for each ID.
The query in your question is not detailed enough to know which of your fields/tables the ID field should come form.

What is the equivalent in SQLite of a MySQL statement, using a sub-select that refers a field alias

The question looks more complicated than the problem itself. So here the example.
I have a "Test" table in MySQL with only one field: ObjectId INTEGER(10).
Values in the ObjectId field:
1
1
1
2
2
I execute the following statement in MySQL query browser:
SELECT DISTINCT ObjectId obid, (SELECT count(*) FROM Test WHERE ObjectId = obid) AS cnt FROM Test
The result is what I expect: in the example above, a number of 2 rows containing:
Column 1: the ObjectId value
Column 2: the number of times the respective ObjectId value appears in the column.
obid cnt
1 3
2 2
Now I execute the same statement on an identical table (structure and data) created in a SQLite database. I get an error telling that "no such column: obid".
The above mentioned SELECT is quite convenient for my purpose. It would look a bit odd to be forced to replace it with a series of selects (like using a cursor). I am new to SQLite, so maybe I miss something. I've investigated a lot with zero results.
So, has anyone an idea if there is a similar, single SELECT statement, that would produce the same result on the SQLite database?
Thanks
You're doing it the complicated way. :) GROUP BY should get what you want.
SELECT ObjectID AS obid, COUNT(1) AS cnt
FROM Test
GROUP BY ObjectID

How can I add a "group" of rows and increment their "group id" in MySQL?

I have the following table my_table with primary key id set to AUTO_INCREMENT.
id group_id data_column
1 1 'data_1a'
2 2 'data_2a'
3 2 'data_2b'
I am stuck trying to build a query that will take an array of data, say ['data_3a', 'data_3b'], and appropriately increment the group_id to yield:
id group_id data_column
1 1 'data_1a'
2 2 'data_2a'
3 2 'data_2b'
4 3 'data_3a'
5 3 'data_3b'
I think it would be easy to do using a WITH clause, but this is not supported in MySQL. I am very new to SQL, so maybe I am organizing my data the wrong way? (A group is supposed to represent a group of files that were uploaded together via a form. Each row is a single file and the the data column stores its path).
The "Psuedo SQL" code I had in mind was:
INSERT INTO my_table (group_id, data_column)
VALUES ($NEXT_GROUP_ID, 'data_3a'), ($NEXT_GROUP_ID, 'data_3b')
LETTING $NEXT_GROUP_ID = (SELECT MAX(group_id) + 1 FROM my_table)
where the made up 'LETTING' clause would only evaluate once at the beginning of the query.
You can start a transaction do a select max(group_id)+1, and then do the inserts. Or even by locking the table so others can't change (insert) to it would be possible
I would rather have a seperate table for the groups if a group represents files which belong together, especially when you maybe want to save meta data about this group (like the uploading user, the date etc.). Otherwise (in this case) you would get redundant data (which is bad – most of the time).
Alternatively, MySQL does have something like variables. Check out http://dev.mysql.com/doc/refman/5.1/en/set-statement.html