I have Two tables in ManyToMany relation:
Table Molécules:
id | main_name | others …
--- | --------- | ------
1 | caféine | others …
Table jsonTextMining:
id | title | molecule_name | others …
---|------- |-------------------------------------|------
1 | title1 | colchicine, cellulose, acid, caféine| others …
and 1 intermediate table:
Table json_text_mining_molecule (it's an exemple i don't succeed to fill it):
json_text_mining_id | molecule_id
------------------------ | ---------------
1 | corresponding molecule id's
1 | corresponding molecule id's
2 | corresponding molecule id's
My problem is that molecule_name in jsonTextMining are a string, i need to separate them before anything.
I tried this :
$molecules = explode (', ', $jsonTextMining→getMoleculeName());
foreach ($molecules as $molecule) {
$jsonTextMining->setMolecule($molecule);
}
$em->persist($jsonTextMining);
$em->flush;
But i think i should loop on jsonTexMining too and to be honnest i'm not sure where to put this part of code. Is it on a random page and the code will execute, should i do a button ?
I know exactly how to fill table with id's when there is a OneToMany relation, i use sql like this :
UPDATE table1 SET id_relation1 = table2.id
FROM table2
WHERE table1.main_name = table2.main_name
But this code fill only one column with id and there's always the matter of string. Is there really a way to get these id's linked so every molecule will have several jsonTextMining ?
You can first split the string using regexp_split function:
select id, regexp_split_to_table(molecule_name,', ') as m_name from jsonTextMining
That will give you a table of ids and names:
id | name
----+------------
1 | acid
1 | caffeine
1 | cellulose
1 | colchicine
Next, you can read from the above, match the names to the ids in the molecule table and aggregate the ids. All put together would result in this:
select s.id, string_agg(m.id::text, ', ')
from (select id, regexp_split_to_table(molecule_name,', ') as m_name
from jsonTextMining) as s, molecules m
where m.main_name = s.m_name group by s.id;
Which gives this result:
id | string_agg
----+------------
1 | 4, 1, 3, 2
(1 row)
If you don't want to aggregate the results and display them one row per molecule then just get rid of string_agg and the group by:
select s.id, m.id
from (select id, regexp_split_to_table(molecule_name,', ') as m_name
from jsonTextMining) as s, molecules m
where m.main_name = s.m_name;
Related
I have two MySQL tables, first, is house and second one family, The house table has two columns called house_id and house_name while the second table has three columns family_id, member_name the last column in the family table used to reference house_id from first table this is house_id
CONCEPT:
How can get number of family_members with/who come from a certain house and put the counted number in the HTML table by fetching only on house table?
I created the following script to fetch from house,
SELECT * FROM house;
And I manipulated the fetched data using foreach like this,
$mystmt = $db -> prepare('SELECT * FROM house');
$mystmt->execute();
$myresult = $mystmt->fetchAll();
foreach($myresult as $mydata) {
$myarray = array();
$myarray[] = $mydata['house_id'];
$myarray[] = $mydata['house_name'];
$output[] = $myarray;
}
echo json_encode($output);
On the above code i get only two columns the house_id and house_name, Now how can i adjust this code to count from family table so that I can get another column called total_family_members
Just like this
family_id | member_name | house_id
1 | John Jackson | 1
2 | Ketty Bebe | 2
3 | Maam Juke | 1
4 | Tike Nuke | 2
5 | Carol Michael | 2
Desired result
house_id | house_name | total_family_members
1 | Joh's house| 2
2 | kim's house| 3
In your example, two different processes are involved:
Link everyone's house id to the house name. This can be achieved with a JOIN.
Count the number of people in each house. This can be achieved with a GROUP BY and a COUNT.
Here is a solution:
SELECT house.house_id , house.house_name , COUNT( * ) AS total_family_members
FROM house
INNER JOIN family ON family.house_id = house.house_id
GROUP BY family.house_id
I have two tables, for simplicity, table A and table B (Note, I don't have the authority to change the structure of these tables, so I'm asking this question to get around a bad database design).
Table A has two columns:
"id" - is the unique identifier.
"customer_id" - is the customer's ID.
So table A holds a list of customer IDs.
Table B holds properties about customers. But it does it in a weird way (again, I didn't set this up, and I can't change it). Table B has [NUMBER] columns:
"id" - is the unique identifier.
"customer_id" - is the customer's ID.
"key" - is the name of the key/value pair
"value" - is the value of the key/value pair
So table B holds key/value pairs that are linked to customers by their ID.
I could join these two tables to get something like this:
+----+-------------+------------+-------+
| id | customer_id | key | value |
+----+-------------+------------+-------+
| 0 | 5 | first_name | Bob |
| 1 | 5 | last_name | Jones |
| 2 | 6 | first_name | Sally |
| 3 | 6 | last_name | Sue |
+----+-------------+------------+-------+
But as you can see, that can be difficult to manage because information about one customer is on two different rows. What would be ideal is something like this:
+----+-------------+------------+-----------+
| id | customer_id | first_name | last_name |
+----+-------------+------------+-----------+
| 0 | 5 | Bob | Jones |
| 1 | 6 | Sally | Sue |
+----+-------------+------------+-----------+
With all of the customer's data on one row.
Is there a way to do this in a SQL query so that I don't have to mess with the results in PHP? Or will I have to pick through the data in PHP?
Given that you cannot alter the table structure, one approach is to use subselects on the customer_id and key:
SELECT
tableA.id,
tableA.customer_id,
(
SELECT
tableB.`value`
FROM tableB
WHERE tableB.customer_id = tableA.customer_id
AND tableB.`key` = 'first_name'
) AS first_name,
(
SELECT
tableB.`value`
FROM tableB
WHERE tableB.customer_id = tableA.customer_id
AND tableB.`key` = 'last_name'
) AS last_name
FROM tableA
Note: Performance-wise this query might suck. But, if you are out of options, maybe the slow query will drive the people who make decisions to allow the structure to be changed.
Use Group_concat or Group by
Select *,Group_concat(value) as full_name
From b left join a on b.customer_id=a.customer_id
Group by customer_id
One method is conditional aggregation:
select (#rn := #rn + 1) as id, customer_id,
max(case when `key` = 'first_name' then value end) as first_name,
max(case when `key` = 'last_name' then value end) as last_name
from b cross join
(select #rn := 0) params
group by customer_id;
I'm not sure what table a would be used for, perhaps for filtering the customer ids.
This will do what you want:
SELECT A.customer_id, B.value, B_1.value
FROM (A INNER JOIN B ON A.customer_id = B.customer_id)
INNER JOIN B AS B_1 ON B.customer_id = B_1.customer_id
WHERE (((B.key)="first_name") AND ((B_1.key)="last_name"));
I have the below table and I want to do the following:
Count the number of times each item appears in the table
Count the DISTINCT number of items
Group the items by name
+-------+---------+
| id | names |
+-------+---------+
| 1 | Apple |
| 2 | Orange |
| 3 | Grape |
| 4 | Apple |
| 5 | Apple |
| 6 | Orange |
| 7 | Apple |
| 8 | Grape |
+-------+---------+
For the 1. and 3. points I have the following query which works quite well:
SELECT * ,
COUNT(names) as count_name,
FROM tbl_products WHERE type = '1'
GROUP BY names
So I get:
Apple (4)
Orange (2)
Grape (2)
Now I want to also count the number of grouped by rows and added a line to count the distinct elements, however there is some problem, since MySQL accepts the query but cannot output a result:
SELECT * ,
COUNT(names) as count_name,
COUNT(DISTINCT names) as count_total
FROM tbl_products WHERE type = '1'
GROUP BY names
Can anyone advice what might be the problem?
EDIT: For more clearance I want to get a table like this:
+-------+---------+------------+-------------+
| id | names | count_ctg | count_total |
+-------+---------+------------+-------------+
| 1 | Apple | 4 | 3 |
| 2 | Orange | 2 | 3 |
| 3 | Grape | 2 | 3 |
+-------+---------+------------+-------------+
Why not just use the query you are using:
SELECT * ,
COUNT(names) as count_name,
FROM tbl_products WHERE type = '1'
GROUP BY names
This query achieves all three objectives.
1) You get a count of the number of each name value in count_name.
2) The number of distinct names values will be equal to the number of rows in the result set , since you are grouping by names. Pretty much any client-side MySQL DB connection library will enable you to retrieve this value.
3) You meet your third criteria of grouping by name by explictly using GROUP BY names
Of course the value for id in the result set is meaningless, you may want to only select names and count_names.
1-.Count the number of times each item appears in the table:
SELECT names, count(names) FROM tbl_products WHERE type = '1' group by names
2-. How many distinct items exist in the table:
SELECT DISTINCT names FROM tbl_products WHERE type = '1'
3-. Group the items by name:
SELECT count(DISTINCT names) as Total FROM tbl_products WHERE type = '1'
As your last EDIT (ALL IN ONE):
SELECT id, names, count(names), total FROM tbl_products, (select count(distinct names) as total from tbl_products) as total WHERE type = '1' group by names
You can get the count of distinct names in a subquery, then OUTER JOIN that thing back into your main query where you already solved for 1 and 3:
SELECT names ,
COUNT(names) as count_name,
Total
FROM tbl_products
OUTER JOIN (SELECT count(DISTINCT names) as Total FROM tbl_products) t2
WHERE type = '1'
GROUP BY names
You can use the SQL Windowing OVER()
This query returns the row_number() function as the id column in the results, and the over(...) for row_number requires an order by clause. You could order by whatever you want, but it most be ordered by something.
;WITH vwGroups (name, Quantity) AS
(
SELECT name
, COUNT(*)
FROM tbl_products
GROUP BY name
)
SELECT ROW_NUMBER() OVER(ORDER BY Quantity DESC, name) AS id
, name
, Quantity AS count_name
, COUNT(*) OVER () AS count_total
FROM vwGroups
Lets say i have a table in my database there looks like this:
|-------------------------|
| id | numbers |
|-------------------------|
| 1 | 1,3,5,7 |
| 2 | 2,4,6,8 |
| 3 | 1,2,3,4,5,6,7,6,8 |
|-------------------------|
I want to remove let us say 4 for all the rows that has the number 4 in the numbers column. What is the sql call to this? I'm using php and mysql.
To make it more understandable I use different table and column names. A better table design would be
users table
-------------------
id
name
other_columns
roles table
-------------
user_id
role_number
Example data:
users
--------------
id name
1 peter
2 tom
roles
----------
user_id role_number
1 1
1 3
1 7
2 2
2 8
Using this design you can now query for all roles a user has like this
select r.role_number
from users u
join roles r on u.id = r.user_id
where u.name = 'peter'
or if you already have the users ID then
select role_number
from roles
where user_id = 1
Using string functions you may try to write following query:
UPDATE
`table_name`
SET
`numbers` = TRIM(BOTH ',' FROM REPLACE(CONCAT(',', `numbers`), ',4', ''))
WHERE
FIND_IN_SET('4', `numbers`);
Test:
SELECT TRIM(BOTH ',' FROM REPLACE(CONCAT(',', '4,2,3,4,5,6,7,6,8,4'), ',4', ''));
Result:
2,3,5,6,7,6,8
A column in my table contains names. I created a query:
SELECT COUNT(*) Number, (b_concat_name) Name FROM `js_b_table` GROUP by Name
that produces the following:
Number | Name
1 | Chris Smith
4 | Fred Savage
2 | Sarah McArthur
How can I update the column b_name_count in js_b_table that contains the corresponding name (b_concat_name) in that row?
If I understand correctly, you want js_b_table to look something like this:
b_concat_name | b_name_count | ... other fields ...
--------------+--------------+---------------------
fred | 3 | ... other values ...
fred | 3 | ... other values ...
fred | 3 | ... other values ...
barney | 2 | ... other values ...
barney | 2 | ... other values ...
where every record's b_name_count indicates the total number of records with the same b_concat_name. Is that correct?
If so, you can use this:
UPDATE js_b_table AS jbt1
INNER
JOIN ( SELECT jbt2.b_concat_name,
COUNT(*) AS b_name_count
FROM js_b_table AS jbt2
GROUP
BY jbt2.b_concat_name
) AS jbt3
ON jbt3.b_concat_name = jbt1.b_concat_name
SET jbt1.b_name_count = jbt3.b_name_count
;
To get a count of how many time each name is in the table it's:
SELECT
count(*) AS number,
name
FROM USERS
GROUP BY name
If I understand correctly, you want to update a column, say name_count, for each user. You can do this by executing the following query:
UPDATE USERS u
SET u.name_count =
(SELECT count(*)
FROM USERS u2
WHERE u2.name = u.name);