MySQL Distinct and LEFT JOIN returns duplicate - php

I have 2 tables in my database. One named data, another named changes.
The table's columns are
Data
------------
|id | name |
|-----------
|1 | Test |
|2 | Hello|
------------
changes
------------------------------------
|id | name | related_id | Comments |
|-----------------------------------
|1 | Test | 1 | Example |
|2 | Hello| 2 | Example2 |
|3 | Hello| 2 | Example3 |
------------------------------------
As you can see, changes.related_id is a foreign key to data.id.
changes can have multiple rows of same name and related_id and different comments.
After running this query, I realized that multiple rows are returned where for example, Hello can appear 2 times.
SELECT DISTINCT data.name, changes.comments FROM data LEFT JOIN changes ON data.id = changes.related_id
Result
--------------------
|name | comments |
|-------------------
|Hello | Example2 |
|Hello | Example3 |
--------------------
How do I go about making sure that only 1 row is returned? I went about SO to look for answers and many stated using DISTINCT, yet it's not working in my case.
Thanks in advance.

If you want only one record for every name in your data table and it can be any record, then you can group by the unique column (name) and use an aggregate function on the other column like max()
SELECT data.name, max(changes.comments)
FROM data
LEFT JOIN changes ON data.id = changes.related_id
GROUP BY data.name

Related

Using Two Tables in PHP & MySQL to display one loop result

Ok so a bit of a funny question here. I have two tables: -
LiveTable
ArchiveTable
The data is as follows: -
Table: LiveTable Table: ArchiveTable
| ID | NAME | | ID | NAME |
------------------ ------------------
| 1 | Test One | | 4 | Test Four |
------------------ ------------------
| 2 | Test Two | | 5 | Test Five |
------------------ ------------------
| 3 | Test Three| | 6 | Test Six |
What I want to do is merge them into one table for querying purposes only. Not as a Database Structure.
In essence when I do a PHP Loop I want the results to work like this: -
Merged Results
| ID | NAME |
------------------
| 1 | Test One |
------------------
| 2 | Test Two |
------------------
| 3 | Test Three|
------------------
| 4 | Test Four |
------------------
| 5 | Test Five |
------------------
| 6 | Test Six |
How would I go about doing this? Also is there a way of doing this with Doctrine?
You can use an SQL query with UNION:
SELECT ID, Name
FROM LiveTable
UNION ALL
SELECT ID, Name
FROM ArchiveTable
Note: UNION ALL will retain duplicates. If you want to remove duplicate records, then use UNION.
Yould use UNION:
SELECT id, name FROM tbl1
UNION ALL
SELECT id, name FROM tbl2
Create DB view using above two tables
CREATE VIEW view_name AS SELECT
id, name FROM tbl1
UNION
id, name FROM tbl2
Then you can query on your view
you can use the sql query multi table select
Select * from LiveTable,ArchiveTable
that's it

Mysql join query multiple values

I have a table called facility.
Structure looks as follows:
id | name
---------
1 | Hotel
2 | Hospital
3 | medical shop
I have an other table which is taking data from the above table and keeping multiple values in one column. View looks like below:
id | facilities
---------------
1 | Hospital~~medical shop~~Hotel
2 | Hospital~~Hotel
3 | medical shop~~Hotel
If I want to join these two tables how does the query look like?
I tried this, but it didn't work:
select overview.facilities as facility
from overview join facility on facility.id=overview.facilities;
you can do this with a bit of hackery
select o.facilities as facility
from overview o
join facility f on find_in_set(f.facilities, replace(o.facilities, '~~', ','));
I would highly recommend you change the way you are storing data. currently it is considered un normalized and that quickly becomes a monster to deal with
you should change your table structure to look something more like this
+----------+--------------+
| facility |
+----------+--------------+
| id | name |
+----------+--------------+
| 1 | Hotel |
| 2 | Hospital |
| 3 | medical shop |
+----------+--------------+
+-----------+-------------+
| overview |
+-----------+-------------+
| id | facility_id |
+-----------+-------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 3 |
| 7 | 1 |
+-----------+-------------+
Code Explanation:
basically you are wanting to find the matching facilities in the overview. one handy function MySQL has is FIND_IN_SET() that allows you to find an item in a comma separated string aka find_in_set(25, '11,23,25,26) would return true and that matching row would be returned... you are separating your facilities with the delimiter ~~ which wont work with find_in_set... so I used REPLACE() to change the ~~ to a comma and then used that in the JOIN condition. you can go from here in multiple ways.. for instance lets say you want the facility id's for the overview.. you just add in the select GROUP_CONCAT(f.id) and you have all of the id's... note if you do that you need to add a GROUP BY at the end of your query to tell it how you want the results grouped

Separating a single linebreak-separated value into multiple values in MySQL

I have a table that puts multiple values into a single value in MySQL, separated by linebreaks. Like this:
+------------+-------------+
| Company | Products |
| (VARCHAR) | (TEXT) |
+------------+-------------+
| Acme Corp | Medicine |
| | Food |
| | Phones |
+------------+-------------+
| Ajax Corp | TVs |
| | Phones |
| | Pianos |
+------------+-------------+
I can't do anything about the table structure. Now I need a query that will return this table:
+==========+
| Products |
+==========+
| Food |
+----------+
| Medicine |
+----------+
| Phones |
+----------+
| Pianos |
+----------+
| TVs |
+----------+
I prefer a pure MySQL approach, but a solution with PHP is also OK for me.
There are no handy ways to split a field with MySQL. (Check the comments in the MySQL documentation). So, the best method seems to obtain all the product records with a simple:
SELECT Products FROM YourTable
And after in you php code:
$products = array_merge($products, explode("\n", $record));
for each record.
This will work for 3 products maximum,for more it needs a bit of tinkering
CREATE TABLE t
(
company varchar(20),
products text
);
INSERT INTO t
VALUES
('Acme', 'Medicine,Food,Phones'),
('ajax', 'TVs,Phones,Pianos');
SELECT SUBSTRING_INDEX(Products,',',1) FROM t
UNION
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',2),',',-1) FROM t
UNION
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',3),',',-1) FROM t
WHERE SUBSTRING_INDEX(Products,',',1)<>''
AND SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',2),',',-1) <>''
AND SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Products,','),',',3),',',-1)<>''
Results
Medicine
TVs
Food
Phones
Pianos

count number of rows that have the same combination of two colums

Hi I have 2 table Offense table and User_jobs table
offense table:
crime_id |crime_type |casenumber|
---------+-----------+----------+
1 | 3 |1 |
2 | 3 |1 |
1 | 3 |2 |
12 | AA |2 |
user_jobs table:
casenumber |disposal_status |
-----------+----------------+
1 | yes |
1 | yes |
2 | no |
2 | no |
what i want is to count the number of rows with the same combination say crime_id=1 and crime_type= 3 but these must have a disposal status of yes in the user_jobs table.
i want to do this in mysql. pliz help
sorry but i am new to mysql. i now want to display the real names of those id not the id themselves.
the tables with these IDs are crime_category and Crime_type Crime_catgory
table:
category |crime_id |
-----------+----------------+
theft | 1 |
murder | 2 |
rape | 3 | 2 |
no |
Crime_type table:
Crime_type |id |
---------------+----------------+
administrative | yes |
criminal | yes |
You can do this with a simple inner join and an aggregate function:
select
o.crime_id,
o.crime_type,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type
This will pick up distinct combinations of the first two columns joined as they should tot he jobs table and only where the disposal_status is equal to 'Yes'
Edit: You would probably do really well to have a read of this Q&A that I put together for exactly this sort of situation - where I give you the code for it, but would like to explain this is a lot more detail. The Q&A explains why this type of thing (and many many others) work and how they do so:
How can an SQL query return data from multiple tables
Edit 2:
select
o.crime_id,
o.crime_type,
ct.category,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
join crime_type ct
on o.crime_type=ct.crime_id
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type,
ct.category,

Join two tables with one table has multiple rows matching

Trying to figure out if it is possible to create a query where you join tables, table one is smaller than table two, table two has multiple references matching table one entries, the query would output a joining where table one length is preserved but you just add more columns. Not sure if that makes sense so here is a example of what I am after
Table One Table two
+-----------------------------+ +-----------------------------+
| id | english | definition | | id | word_id | sentence |
+-----------------------------+ +-----------------------------+
|1 | A1 | blah | |1 | 1 | blahblah1 |
|2 | B4 | blah2 | |2 | 1 | blahblah2 |
+-----------------------------+ |3 | 1 | blahblah3 |
|4 | 2 | blahblah4 |
|5 | 2 | blahblah5 |
+-----------------------------+
********* Query should return something like *****************
+----------------------------------------------------------------+
| id | english | definition | sentence | sentence2 | sentence3 |
+----------------------------------------------------------------+
|1 | A1 | blah | blahblah1| blahblah2| blahblah3 |
|2 | B4 | blah2 | blahblah4| blahblah5| |
+----------------------------------------------------------------+
My Current query looks like this and results in:
$query = "SELECT * FROM T1 INNER JOIN T2 ON T1.id = T2.word_id";
Resulting in:
+----------------------------------------+
| id | english | definition | sentence |
+----------------------------------------+
|1 | A1 | blah | blahblah1|
|1 | A1 | blah | blahblah2|
|1 | A1 | blah | blahblah3|
|2 | B4 | blah2 | blahblah4|
|2 | B4 | blah2 | blahblah5|
+----------------------------------------+
I am working with PHP and MySql.
UPDATE!!
Staying with my original query and manipulating the results with PHP getting good performance too. Let me know if you need me to post my code.
You might be looking for GROUP_CONCAT()
SELECT T1.id, T1.english,T1.definition,
GROUP_CONCAT(T2.sentence ORDER BY T2.ID SEPARATOR '|')
FROM Table1 T1 INNER JOIN Table2 T2 ON T1.id = T2.word_id
Group by word_id
Sample fiddle
The answer is NO. Simply because there's unknown number of columns (say, if you add one more sentence to the top word you could be adding one more column to the result set) and each column is not well defined ( Why blahblah4 should be in column sentence instead of sentence2 ?)
IMO, SQL is used to tell what you want to get, but in this case, SQL is unable to tell exactly what you want.
Even if this can be done ( I would love to learn ), I believe the complexity offsets any benefit and handling this in PHP is a better option.

Categories