Distinct number of specific items in list - mysql

I rarely do stuff in MySQL, so for me this is rocket science ...
I want to know how many times distinct values starting with "abc-" are present in a list.
So for example how many times "abc-table" and "abc-sofa" are present.
The table:
| object
-----------
| abc-table
| def-table
| ghi-chair
| abc-sofa
| abc-table
The result should be like:
| name number
-------------------
| abc-table 2
| abc-sofa 1
(Excuse me for the badly formatted tables.)
I tried the following, but that turns out to be incorrect:
SELECT object, COUNT(DISTINCT object) WHERE object LIKE abc-% FROM table GROUP BY object
Any help is appreciated.

WHERE clause should be after FROM.
Use single quote ' for the LIKE operator.
No need of DISTINCT in your case.
Try the below query:
SELECT `object` AS `name`, COUNT(`object`) AS `number`
FROM table
WHERE `object` LIKE 'abc-%'
GROUP BY `object`
ORDER BY COUNT(`object`) DESC; -- add order by if you need to sort by count
Result:
name number
----------------
abc-table 2
abc-sofa 1
DEMO

Use count(*), groupt by , like 'abc-%' and having
SELECT object, COUNT(*)
FROM table
WHERE object LIKE 'abc-%'
group by object
having count(*) >=1

Related

Mysql - How do I avoid group by but still with concat and group concat I would need to combine multiple columns and rows results

I have something like in table
mysql> select uuid , short-uuid FROM sampleUUID WHERE identifier ="test123";
+--------------------------------------+-------------+
| uuid | short-uuid |
+--------------------------------------+-------------+
| 11d52ebd-1404-115d-903e-8033863ee848 | 8033863ee848 |
| 22b6f783-aeaf-1195-97ef-a6d8c47261b1 | 8033863ee848 |
| 33c51085-ccd8-1119-ac37-332510a16e1b | 332510a16e1b |
+--------------------------------------+-------------+
I would be needing a result like (grouped all in single row, single value w.r.t uuid and short-uuid being same)
| uuidDetails
+----------------------------------------------------------------------------------------------------------------+-------------+
| 11d52ebd-1404-115d-903e-8033863ee848,22b6f783-aeaf-1195-97ef-a6d8c47261b1|8033863ee848&&33c51085-ccd8-1119-ac37-332510a16e1b| 332510a16e1b |
+----------------------------------------------------------------------------------------------------------------+-------------+
(basically grouping uuid and short uuid in a single row from multiple rows and columns)
I know this can be achieved by select GROUP_CONCAT(uuid)FROM sampleUUID WHERE identifier ="test123" group by short-uuid;
but i don't wanna use group by here because that give multiple rows, i would need all in one row .
I have tried with below stuffs but failed to get the the results in single row
select ANY_VALUE(CONCAT_WS( '||',CONCAT_WS('|',GROUP_CONCAT(uuid) SEPARATOR ','),short-uuid)) )as uuidDetails from sampleUUID
where identifier ="test123";
this resulted like below with not appending short-uuid properly (there is only 1 short uuid appended here,Actually it needs to be grouped first 2 uuids with 1 short(because same short-uuid) uuid and 3rd uuid with other short uuid)
| uuidDetails
+----------------------------------------------------------------------------------------------------------------+-------------+
| 11d52ebd-1404-115d-903e-8033863ee848,22b6f783-aeaf-1195-97ef-a6d8c47261b1,33c51085-ccd8-1119-ac37-332510a16e1b| 332510a16e1b |
+----------------------------------------------------------------------------------------------------------------+-------------+
which is not i expected
Any help here will be appreciated . Thank you
Use nested queries.
SELECT GROUP_CONCAT(result ORDER BY result SEPARATOR '&&') AS uuidDetails
FROM (
SELECT CONCAT(GROUP_CONCAT(uuid ORDER BY uuid SEPARATOR ','), '|', short_uid) AS result
FROM sampleUUID
WHERE identifier = 'test123'
GROUP BY short_uid
) AS x
NOTE: If there is no requirement for ordering of the UUID values, we can use ORDER BY inside the GROUP_CONCAT aggregates to make the result more deterministic, so the query will return just one of a number of possible results given the same data e.g. return aa,bb|1&&cc|3 rather than bb,aa|1&&cc|3 or cc|3&&aa,bb|1 or cc|3&&bb,aa|1.

Sum and percentage on json array elements

My table is like this:
create table alphabet_soup(
id numeric,
index json bigint
);
my data looks like this:
(id, json) looks like this: (1, '{('key':1,'value':"A"),('key':2,'value':"C"),('key':3,'value':"C")...(600,"B")}')
How do I sum across the json for number of A and number of B and do % of the occurence of A or B? I have about 6 different types of values (ABCDEF), but for simplicity I am just looking for a comparison of 3 values.
I am trying to find something to help me calculate the % of occurrence of a value from a key value pair in json. I am using postgres 9.4. I am new to both json and postgres, and I am landing on the same json functions manual page of postgres over and over.
I have managed to find a sum, but how to calculate the % in a nested select and display the key and values in increasing order of occurence like follows:
value | occurence | %
====================================
A | 300 | 50
B | 198 | 33
C | 102 | 17
The script I am using for the sum is :
select id, index->'key'::key as key
sum(case when (1,index::json->'1')::text = (1,index::json->'2')::text
then 1
else 0
end)/count(id) as res
from
alphabet_soup
group by id;
limit 10;
I get an output as follows:
column "alphabet_soup.id" must appear in the group by clause or be used in an aggregate function.
Thanks for the comment Patrick. Sorry I forgot to add I am using postgres 9.4
The easiest way to do this is to expand the json document into a regular row set using the json_each_text() function. Every single json document then becomes a set of rows and you can then apply aggregate function as you would on any other row set. However, you need to use the function as a row source (section 7.2.1.4) (since it returns a set of rows) and then select the value field which has the category of interest. Note that the function uses a field of the table, through an implicit LATERAL join (section 7.2.1.5).
SELECT id, value
FROM alphabet_soup, json_each_text("index");
which yields something like:
test=# SELECT id, value FROM alphabet_soup, json_each_text("index");
id | value
----+-------
1 | A
1 | C
1 | C
1 | B
To this you can apply regular aggregate functions over the appropriate windows to get the result you are looking for:
SELECT DISTINCT id, value,
count(value) OVER (PARTITION BY id, value) AS occurrence,
count(value) OVER (PARTITION BY id, value) * 100.0 /
count(id) OVER (PARTITION BY id) AS percentage
FROM (
SELECT id, value
FROM alphabet_soup, json_each_text("index") ) sub
ORDER BY id, value;
Which gives a result like:
id | value | occurrence | percentage
----+-------+------------+---------------------
1 | A | 1 | 25.0000000000000000
1 | B | 1 | 25.0000000000000000
1 | C | 2 | 50.0000000000000000
This will work for any number of categories (ABCDEF) and any number of ids.
# Patrick, it was an accident. I am new to stackoverflow. I did not realize how ti works. I was fiddling around and I found the answer to the question I asked in addition to the first one. Sorry about that!
For fun, I added some more to the code to make the % compare of the result set:
With q1 as
(SELECT DISTINCT id, value,
count(value) OVER (PARTITION BY id, value) AS occurrence,
count(value) OVER (PARTITION BY id, value) * 100.0 / count(id) OVER(PARTITION BY id) AS percentage
FROM ( SELECT id, value FROM alphabet_soup, json_each_text("index") ) sub
ORDER BY id, value) Select distinct id, value, least(percentage) from q1
Where (least(percentage))>20 Order by id, value;
The output for this is:
id | value | least
----+-------+--------
1 | B | 33
1 | C | 50

Single query for several selects -even if one select returns empty

I need to make several select statements to get simple data (only one row containing one or several fields for each select).
Simplified example:
select name, price from article where id=125
select log, email from user where uid=241
I want to process only one single statement from php side (or: I do NOT want to prepare several statements, execute several statements, catch and handle exceptions for each execution and finally fetch result for each statement...).
I tried:
select * from (
(select name, price from article where id=125) as a,
(select log, email from user where uid=241) as b
)
which works great if every subselect returns values:
name | price | log | email
------------------------------------------
dummy | 12,04 | john | john#example.com
But if one of the subselects returns empty, the whole select returns empty.
What I want is: null values for empty resulting subselects.
I tried many things with ifnull() and coalesce(), but couldn't get the awaited result (I know how to use them with null values, but I didn't find a way to deal with them in the case of an empty result set).
I finally found a solution with left joins:
select * from (
(select 1) as thisWillNeverReturnEmpty
left join (select name, price from article where id=125) as a on 1
left join (select log, email from user where uid=241) as b on 1
)
which works perfectly even if one of the subqueries returns empty (or even both, therefore the "select 1").
Another way I found on SO would be to add a count(*) in each subquery to make sure there's a value.
But it all looks quite dirty and I can't believe there's no simple way just using something like ifnull().
What is the right way to do it?
The best way I finally found was:
select * from (
(select count(*) as nbArt, name, price from article where id=125) as a,
(select count(*) as nbUser, log, email from user where uid=241) as b
)
This way, no subquery ever returns empty, which solves the problem (there's always at least a "zero" count followed by null values).
Sample result when no article is found:
nbArt | name | price | nbUser | log | email
----------------------------------------------------------------
0 | null | null | 1 | john | john#example.com

MySQL select column name and value as a field

I have a mysql table that looks something like this:
id | PO | DAP | MEDIA
---|----|-------|------
1 | 2 | 34 | 64
2 | 6 | 53 | 23
I would like to be able to query get multiple rows, one for each column. E.g:
SELECT column_name as column, column_value as value FROM my_table;
Which would give me:
PO=2,DAP=34,MEDIA=54,PO=6,DAP=53,MEDIA=23
What would I need to use to formulate a query like this?
You have to first CONCAT the data of each specified field and apply GROUP_CONCAT ON the result.
Query
SELECT GROUP_CONCAT(temp_col) FROM
(
SELECT 1 as 'temp_id',
CONCAT(
CONCAT('PO=', PO),
',',
CONCAT('DAP=', DAP),
',',
CONCAT('MEDIA=', MEDIA)
) AS 'temp_col'
FROM test
) temp
GROUP BY temp_id
Check Out SQLFIDDLE
Not exactly sure what you mean. But this is traditionally done in this manner
SELECT * FROM my_table;
You'll get your array like this
array(0=>array('PO'=>2,'DAP'=>34,'MEDIA'=54), 1=>array('PO'=>6, 'DAP'=>53, 'MEDIA'=> 23))
.. like so.

Select row which contains exact number in column with set of numbers separated by comma

Maybe answer is very easy, but I can't find the right MySQL query which do what I want.
I have table user :
| id_user | name | action_type |
+---------------------------------+
| 1 | joshua | 1,13,12,40 |
| 2 | joshua | 2,8 |
And I want to select only rows which have exact number in action_type column.
action_type is stored in MySQL as TEXT.
I've tried this:
SELECT * FROM user WHERE action_type LIKE '%2%'
But it selected rows with 12 which is not what I want :(
Maybe it's possible with IN operator, but I couldn't find a right way to use this.
You are looking for FIND_IN_SET
SELECT *
FROM user
WHERE FIND_IN_SET( '2', action_type )
SQL Fiddle DEMO
UPDATE
Just to mentioned it, this is also possible
SELECT *
FROM user
WHERE FIND_IN_SET( 2, action_type )
MySQL will do an automatic conversion to char
Include the delimiter in your LIKE clause:
SELECT *
FROM user
WHERE action_type LIKE '2,%'
OR action_type LIKE '%,2,%'
OR action_type LIKE '%,2'
Note that I had to use two additional LIKE clauses to cover the cases where the item is at the beginning or end of the string.
Try
SELECT * FROM user
WHERE CONCAT( ',', action_type, ',' ) LIKE '%,2,%';
correct syntax from Sir Rufo