Group by X or Y? - mysql

I'm trying to figure out how to GROUP BY on multiple columns. I want to group items when the SSN or the address matches. For example, here are three records:
account_number | name | ssn | address
---------------+--------------+-------------+----------------------
23952352340 | SMITH INC | 123-45-6789 | P.O. BOX 123
3459450340 | JOHN SMITH | 123-45-6789 | 123 EVERGREEN TERRACE
45949459494 | JANE SMITH | 395-23-1924 | 123 EVERGREEN TERRACE
And here's what I'd like to end up with:
names
----------------------
SMITH INC, JOHN SMITH, JANE SMITH
Any suggestions?

You can't do this easily in MySQL.
The problem is that the relation "is similar to" as you define it is not transitive. In your example, Smith Inc is similar to John Smith (per SSN) and John Smith is similar to Jane Smith (per name), but Smith Inc is not similar to Jane Smith. So there is no single value that all records could be compared with and GROUP BY won't help here.
In other systems which support recursion you could build a transitive closure of this relation which would allow grouping, but this is not an easy task in MySQL.

Like this:
SELECT
name,
ssn,
COUNT(*)
FROM TheTable
GROUP BY
name,
ssn

Related

How to search for multiple terms using AND in a SQL query?

I have a simple web app listing different data types in searchable tables.
I'm using MySQL for the database.
For example, there's a list of Employees with FirstName, LastName, and so on.
Example Employees table:
ID | FIRSTNAME | LASTNAME | EMAILADDRESS
---------------------------------------------
001 | John | Smith | js#gmail.com
002 | John | Jones | jj#gmail.com
003 | Michael | Smith | ms#gmail.com
004 | Betty | Taylor-Smith | bts#gmail.com
There's a simple text field for searches.
Search for John Smith results are anything has a John AND Smith in it:
001 | John | Smith
Search for John, results are anything that has John in it:
001 | John | Smith
002 | John | Jones
Search for Smith, results are anything that has Smith in it:
001 | John | Smith
003 | Michael | Smith
004 | Betty | Taylor-Smith
So ... my question is ... how should I write the SQL query for this?
select * from employees where ...
If I search for John Smith ...
((firstname like "%John%") OR (firstname like "%Smith%"))
AND
((lastname like "%John%") OR (lastname like "%Smith%"));
AND
((emailaddress like "%John%") OR (emailaddress like "%Smith%"));
Returns zero results because the emailaddress doesn't match.
If I change ANDs to ORs ...
((firstname like "%John%") OR (firstname like "%Smith%"))
OR
((lastname like "%John%") OR (lastname like "%Smith%"));
OR
((emailaddress like "%John%") OR (emailaddress like "%Smith%"));
Then I get all four results because there's a John or a Smith in every row ... which is not the result I want, I only want the first row 001.
001 | John | Smith | js#gmail.com
002 | John | Jones | jj#gmail.com
003 | Michael | Smith | ms#gmail.com
003 | Betty | Taylor-Smith | bts#gmail.com
How should I approach this SQL query?
Seems like you want:
((firstname LIKE "%John%") OR (lastname LIKE "%John%") OR (emailaddress LIKE "%John%"))
AND
((firstname LIKE "%Smith%") OR (lastname LIKE "%Smith%") OR (emailaddress LIKE "%Smith%"))
Could you potentially use CONCAT_WS to meet your requirements?
SELECT *
FROM employees
WHERE CONCAT_WS(" ", firstname, lastname) LIKE "%John Smith%"
OR firstname LIKE "%John Smith%" # in case user provides just a first name
OR lastname LIKE "%John Smith%" # in case user provides just a last name
OR emailaddress LIKE "%John Smith%" # support searching by e-mail at the same time

MySQL Query using data from two tables

I have two tables like so:
Table 1: tracks
id | artist | track
---------------------------------------
1 Tom Smith This Time is Right Time
2 Tom Smith Oh Yes
3 John Doe Every Time I See You
Table 2: festival_bands
id | fest_title | fest_artist
---------------------------------------
1 Hoe Down Fest 2019 John Doe
2 Copperland Fest Tom Smith
3 Copperland Fest Reggie Wisk
4 Copperland Fest Tom Smith
5 Copperland Fest John Doe
6 Bluegrass Memories John Doe
I need to show only ONE "track" from table 1 for each festival listing from Table 2 like so:
Results:
Copperland Festival:
-----------------------
Tom Smith This Time is Right Time
John Doe Every Time I See You
In layman's terms, the logic would be along the lines of:
Get only one track from TABLE 1 where artist equals (or matches) fest_artist from TABLE 2
I referenced a similar question which advised something in the direction of:
$sql="select * from tracks WHERE (artist) in (select fest_artist from festival_bands group by name)" but with no luck.
You can use a correlated subquery to get a random track for the artist:
select fb.*,
(select t.track
from tracks t
where t.artist = fb.fest_artist
order by t.counter desc
) as most_popular_track
from festival_bands fb;

Optimising table design or optimising the query

I am trying to decide which one is better: to design a table that wastes a lot of space and has a simple query OR to write a very tight table but then the process of finding what I am looking for would be very processing intense.
The actual problem is this:
Imagine you have a very simple table. 1st column for the ID number the 2nd is a list of names and the 3rd is a list of names too. The 2nd column is a list of people who owe to the people in the 3rd column.
The search should do the following:
I search for a name in the 3rd column and see who owes this person in the 2nd column. A name or multiple names come up, then I want to see who owes them, again a bunch of names come up, and so on to level 5.
Maybe this is a well known scheme for which there is a well known simple answer in table design or MySQL circles. Could anybody suggest a MySQL query or perhaps an appropriate table design where I can use a simple query?
Example
ID owes owned to
1 Peter John
2 John George
3 Abdul George
4 George Anna
So I could design a wasteful table like this
ID 1 2 3 4 5
1 Anna George Abdul
2 Anna George John Peter
3 George Abdul
4 George John Peter
5 John Peter
But this would be very wasteful and bad bad design but it would be very easy to access the data along with the hierarchy and the owing chain.
Something like this seems suitable:
people
+----+--------+
| id | name |
+----+--------+
| 1 | Marty |
| 2 | Steven |
| 3 | John |
+----+--------+
With the table building the relationships between people owed and owing:
loans
+-----------+-------------+
| lender_id | borrower_id |
+-----------+-------------+
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
+-----------+-------------+
You could get all the people owing a given lender with something as simple as:
SELECT people.id, people.name
FROM loans
INNER JOIN people ON people.id = loans.borrower_id
WHERE loans.lender_id = X
Where X is the id of the lender. Given the lender_id of 1 (Marty) for example would yield:
+----+--------+
| id | name |
+----+--------+
| 2 | Steven |
| 3 | John |
+----+--------+
You can repeat this process for each of the resulting people until there are no results (no one being owed).

Select all rows which column has not already returned existing result

I am trying to pull records up from a mysql database but I want the result in one column to be completely unique
below is an example table
fname | lname | Street
-----------------------
john | brown | camelot st
george | kent | camelot st
fred | kent | johnston rd
jane |williams| camelot st
jack | johnson| archer dr
james | smith | bruce st
adam | smith | james dr
below is the results I would want
Street
-----------
camelot st
johnston rd
archer dr
bruce st
james dr
in other words the first time any street name is returned it should display in the results after the first time it is no longer unique in the result and it should be omitted.
How would I manage this in mysql
SELECT * FROM tableName
WHERE street IN (
SELECT DISTINCT street FROM tableName
) LIMIT 1;
This query should answer your question. However, it is important to note that you should order by an id field, because otherwise there is no guarantee that the rows in your database will always be queried in the same order.

MySQl update column with values in a specific format

I am working on an old application and mysql db that is sadly all in a bit of a mess.
I am interested in a column needed for export that contains names of editors for particular documents. The values in this column should be formatted in a particular way, and should be consistent which they are currently not.
A document can have many editors. I have a table containing all distinct editors which I need to seomhow match against the current (incorrectly formatted) editors value. I know this is not the best way to go about doing this (it is how the application currently works) but I need the editors column to be formatted as follows:
"Surname, Initial. and Surname, Initial. and Surname, Initial"
E.g.:
"Bloggs, J. and Doe, J."
"Smith, M.J. and Bloggs, J. and Jones, P"
"Williams, S. and Smith, M.J. Doe, J."
However the column is currently inconsistent with no real formatting in place:
"J Bloggs, J Doe"
"MJ Smith, J Bloggs and P Jones"
"Williams, S, M.J Smith. Doe, J."
etc...
Here are my current tables:
Documents:
| title | editors |
------------------------------------------------
| doc title 1 | J Bloggs, J Doe |
| doc title 2 | M Smith, J Bloggs and P Jones |
| doc title 3 | Williams, S, M Smith. Doe, J. |
Eitors:
| initial | name |
------------------------
| J. | Bloggs |
| J. | Doe |
| M.J. | Smith |
| P. | Jones |
| S. | Williams |
For testing purposes I have added a column (formatted_editors) to the Documents table:
| title | editors | formatted_editors |
---------------------------------------------------------------------------------
Which I need to look something like this:
| title | editors | formatted_editors |
---------------------------------------------------------------------------------
| doc title 1 | J Bloggs, J Doe | Bloggs, J. and Doe, J.
| doc title 2 | M Smith, J Bloggs and P Jones | Smith, M.J. and Bloggs, J. and Jones, P
| doc title 3 | Williams, S, M Smith. Doe, J. | Williams, S. and Smith, M.J. Doe, J.
I have tried the following (and various others) but cant seem to have any luck - I think it may have something to do with my groupings ?
SELECT d. title, d.editors, group_concat(e.name, ', ', e.initial SEPARATOR ' and ') as formatted_editors
FROM documents d
INNER JOIN editors e
ON d.editors LIKE concat('%', e.name, '%')
WHERE d.editors LIKE concat('%', e.name, '%')
and et.editors LIKE concat('%', e.initial, '%')
GROUP BY et.editors;
Any help / pointers would be appreciated,
No "real" reliable way to solve this then... I used some basic SQL to fix up / match what I can and did the rest manually.
Thanks,
Jon.