Combine 2 values to 1 column MySQL - mysql

Code:
SELECT s.*, k.address FROM student s
INNER JOIN address k
ON instr(s.fulladdress, k.address) > 0
WHERE j.phonetic like '%california%'
This result will display 2 rows with 2 parts of address:
30,Andre Hans, Address 1 Address 2,class IBA1001, Address 1
30,Andre Hans, Address 1 Address 2,class IBA1001, Address 2
I want to display it in 1 row:
30,Andre Hans, Address 1 Address 2,class IBA1001, Address 1 | Address 2
How i can do that?

Use group by and group_concat:
SELECT s.*, group_concat(k.address separator ' | ') FROM student s
INNER JOIN address k
ON instr(s.fulladdress, k.address) > 0
WHERE j.phonetic like '%california%'
GROUP BY s.col1, s.col2 .... -- all the columns in table student

Related

Join multiple tables with Having expression

There are 2 tables Contacts & BlockedEntries
Table: Contact
Id
FirstName
LastName
Email
JobTitle
Table: BlockedEntries
Id
Email
Trying to find the entries from contact table with more than one occurence of blockedEntries
SELECT email, COUNT(*) as cc, GROUP_CONCAT( id SEPARATOR '#') AS ContactIds
FROM contacts
where email IN (SELECT email FROM BlockedEntries)
GROUP BY email
HAVING COUNT(*) > 1
Is there any way to get some more additional details like first name ,last Name, email,job title etc for the entries with count is more than 1
Unfortunately there is no relation between these 2 tables and email is the only possible mapping . There can be 1 or more entries present in COntact table with same email address
Sample data
Id FirstName LastName Email JobTitle
12 sam j samj#gmail.com engineer
23 bos j bosj#gmail.com accountnt
34 cas j samj#gmail.com engineer
33 xxx j bosj#gmail.com fied
55 dfe c dfe#gmail.com student
Table: BlockedEntries
Id Email CreateDate
1 samj#gmail.com 09/12/2020 19:30:20
2 bosj#gmail.com 09/12/2020 19:30:20
3 dfe#gmail.com 09/12/2020 19:30:20
Result expecting
email id firstname lastName jobtitle
samj#gmail.com 12 sam j engineer
samj#gmail.com 34 bos j accountnt
bosj#gmail.com 23 cas j engineer
bosj#gmail.com 33 xxx j fied
dfe#gmail.com only 1 instance and no need to add this to result set
On MySQL 8+, I would use COUNT() as an analytic function here:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY email) email_cnt
FROM contacts
)
SELECT c.Id, c.FirstName, c.LastName, c.Email, c.JobTitle
FROM cte c
WHERE email_cnt > 1 AND
EXISTS (
SELECT 1
FROM BlockedEntries be
WHERE be.email = c.email
);
Based on your data example you just need two inner joins, one with the BlockedEntries which will get you all the related emails between BlockedEntries and Contact table and another join with a subquery which will get the emails more than once on Contact table.
Try:
select c.Id,
c.FirstName,
c.LastName,
c.Email,
c.JobTitle
from Contact c
inner join BlockedEntries be on be.Email=c.Email
inner join (select Email
from Contact
group by Email
having count(*)>1
) as cnt on cnt.Email=c.Email;
https://dbfiddle.uk/P9Y4RHfu

MySQL: Add multiple columns after GROUP BY?

I am trying to do following:
SELECT
customer_entity.email,
customer_entity.website_id
FROM
customer_entity
INNER JOIN
(SELECT
email
FROM
customer_entity
GROUP BY email
HAVING COUNT(email) > 1) dupes
ON customer_entity.email = dupes.email
GROUP BY customer_entity.`entity_id`
ORDER BY customer_entity.email ;
Above query returns the result below:
email website_id
abe#abc.com 1
abe#abc.com 2
abe#abc.com 3
abe#abc.com 4
test#abc.com 1
test#abc.com 2
test#abc.com 4
xyz#abc.tv 1
xyz#abc.tv 2
xyz#abc.tv 3
But I want data in below format:
email website1 website2 website3 website4
abe#abc.com 1 2 3 4
test#abc.com 1 2 null 4
xyz#abc.tv 1 2 3 null
is it possible in this case?
Thanks
You can do conditional aggregation:
select
email,
max(website_id = 1) website_1,
max(website_id = 2) website_2,
max(website_id = 3) website_3,
max(website_id = 4) website_4
from customer_entity
group by email
having count(*) > 1
order by email
Note that this simplifies your original query - a self-join is not needed here.
Also, this puts 0/1 values in each column that indicates whether the given email exists for this website - I find that it is more meaningful than repeating the website id in the column.

SQL JOIN as single row with child values as columns and ability to ORDER BY child relationship value

I don't know what the right definition of this is, but its more dynamic than a regular relationship join.
contacts:
id, first_name, last_name
fields:
id, handle, type
field_values:
id, field_id, contact_id, value
The table fields is not that important in this, but wanted to give context.
Example of contacts table:
id first_name last_name
-- ----- --------
1 John Doe
2 Jane Smith
Example of field value table:
id contact_id field_id value
-- ----- -------- ------
1 1 1 Boston
2 1 2 johndoe#mail.com
3 2 1 Seattle
3 2 2 janesmith#mail.com
In this basic example, you can see that there are 2 fields, one for location (boston, seattle) and one for email. When I put them into a JOIN query they look like this
SELECT * FROM contacts LEFT JOIN field_values ON contacts.id = field_values.contact_id;
Example of contacts JOIN field values table:
id first_name last_name field_id value
-- ----- -------- ------ -------
1 John Doe 1 Boston
1 John Doe 2 johndoe#mail.com
2 Jane Smith 1 Seattle
2 Jane Smith 2 janesmith#mail.com
TWO QUESTIONS:
1) How do I ORDER BY the field value. So I want to order by the field email which is field id = 2.
2) Is it possible to get a single row for each contact and each field value as a new column?
Example: Single row per contact?
id first_name last_name field_id(2) field_id(1)
-- ----- -------- ------ -------
1 John Doe johndoe#mail.com Boston
2 Jane Smith janesmith#mail.com Seattle
Single row per contact:
SELECT
contacts.id,
contacts.first_name,
contacts.last_name,
GROUP_CONCAT(IF(field_values.field_id = 2, field_values.value, NULL)) AS email,
GROUP_CONCAT(IF(field_values.field_id = 1, field_values.value, NULL)) AS field_1
FROM contacts
LEFT JOIN field_values ON contacts.id = field_values.contact_id
GROUP BY contacts.id
ORDER BY email;. -- it is optional, only include if you want to sort result by ascending emails.
You may use pivoting logic here to turn out the email and city as separate columns:
SELECT
c.id,
c.first_name,
c.last_name,
MAX(CASE WHEN fv.field_id = 2 THEN fv.value END) AS email,
MAX(CASE WHEN fv.field_id = 1 THEN fv.value END) AS city
FROM contacts c
LEFT JOIN field_values fv
ON c.id = fv.contact_id
GROUP BY
c.id,
c.first_name,
c.last_name;

multiple values in 1 column when you join 2 tables

table 1 - employee
id empname
--------------
1 andy
2 brady
table 2 - employee phone numbers
id number empid
----------------
1 1111 1
2 2222 2
3 3333 1
4 4444 1
Need a sql query to display the following
id empname numbers
------------------
1 andy 1111,3333,4444
2 brady 2222
If you are using MySQL, you can use GROUP_CONCAT funcion, that basically concatenate every value composing the group. You could try this:
SELECT EMP.ID,
EMP.EMPNAME,
GROUP_CONCAT(EPH.NUMBER) AS NUMBERS
FROM EMPLOYEE EMP
JOIN EMPLOYEE_PHONE EPH
ON EMP.ID = EPH.EMPID
GROUP BY EMP.ID
Also, if you want to separate your values with something different of a "," you can add the syntax SEPARATOR " " after the column inside group concat, if you want to separate with spaces in this particular example
if you use SQL SERVER I think this will do it for you, if not maybe a close guess without data. But! I used STUFF and selected the Number and split them by , and ordered it
SELECT
t1.ID,t2v1.empname,
STUFF((SELECT ',' + t2v2.number
FROM Table2 t2v2
WHERE t2v2.ID = t2v1.ID
ORDER BY number
FOR XML PATH('')), 1, 1, '') [numbers]
FROM Table1 t1
inner join table2 t2v1 on t1.id = t2v1.id
GROUP BY t1.ID, t1.Name
ORDER BY 1
Try this:
SELECT e.id, e.name, CONCATENATE(ep.number, ',') as phonelist
FROM Employees e INNER JOIN EmployeePhone ep ON e.id = ep.empid
Reference Doc: http://www.peteonsoftware.com/index.php/2009/12/11/creating-a-comma-separated-list-from-a-sql-grouping/

Check if an employee email contains his name - not a case sensitive

I would like to display the name and the email associated with it when the employee name is contained within the email. A user can have more than one email.
employee
id name
1 Steve Been
2 Rob Kem
3 Bob Kimi
Emails
emplyee_id email
1 steve#domain.com
1 007#domain.com
1 Been#domain.com
2 Robkem#domain.com
2 Rob.Kem#domain.com
3 Boooob#domain.com
3 kimi#domain.com
The query should not be case sensitive. I would like this query to show me something like:
name email
Steve Been steve#domain.com
Steve Been Been#domain.com
Rob Kem Robkem#domain.com
Rob Kem Rob.Kem#domain.com
Bob Kimi kimi#domain.com
I tried this but I got empty output:
select empl.Name as 'employee Name', em.email as 'Product Name'
from email em JOIN employee empl
ON em.employee_id = empl.ID
WHERE FIND_IN_SET(LOWER(empl.Name),LOWER(em.Name))
Try
SELECT e.name,
m.email
FROM emails m JOIN
employee e ON m.emplyee_id = e.id
WHERE INSTR(m.email, SUBSTRING_INDEX(e.name, ' ', 1)) > 0
OR INSTR(m.email, SUBSTRING_INDEX(e.name, ' ', -1)) > 0
SQLFiddle
INSTR() is case insensitive unless one of the stings is a binary string, but you can always add LOWER() for a good measure.
UPDATE: As per your additional request you can do that with a query like this
SELECT name,
total,
matched,
total - matched unmatched
FROM (
SELECT e.name,
COUNT(*) total,
SUM(CASE WHEN INSTR(m.email, SUBSTRING_INDEX(e.name, ' ', 1)) > 0
OR INSTR(m.email, SUBSTRING_INDEX(e.name, ' ', -1)) THEN 1 ELSE 0 END) matched
FROM emails m JOIN
employee e ON m.emplyee_id = e.id
GROUP BY e.id, e.name) q
SQLFiddle