mysql query two tables - mysql

I need to query two tables like this...
table one
customers
id companyname phone
1 | microsoft | 888-888-8888
2 | yahoo | 588-555-8874
3 | google | 225-558-4421
etc...
table two
contacts
id companyid name phone
1 | 1 | sam | 558-998-5541
2 | 1 | john | 558-998-1154
3 | 3 | larry | 111-145-7885
4 | 3 | dave | 558-998-5254
5 | 2 | sam | 558-997-5421
I need to query both tables.
So if I search for sam
it should return a list of companies with the contacts
microsoft 888-888-8888
sam 558-998-5541
john 558-998-1154
yahoo 588-555-8874
sam 558-997-5421
so it returns all company with sam and all contacts with it....
same is if I would search 'microsoft' it should return without yahoo
microsoft 888-888-8888
sam 558-998-5541
john 558-998-1154
and if I search "558-998-1154" it should return like this...
microsoft 888-888-8888
sam 558-998-5541
john 558-998-1154
I hope this is clear....
Here is my current query:
SELECT * FROM
customers, customer_contacts
WHERE (customers.code LIKE '%#URL.qm1#%'
or customers.COMPANY LIKE '%#URL.qm1#%'
or customers.phone LIKE '%#URL.qm1#%'
or customers.contact LIKE '%#URL.qm1#%'
or customers.name LIKE '%#URL.qm1#%'
or customers.address1 LIKE '%#URL.qm1#%')
AND (customers.id = customer_contacts.cid
and customer_contacts.deleted = 0)
this returns only those who have a contact...
I would need
it to return the ones without contacts as well.

This is a sticky problem, one that I almost want to say "don't try to do this is one query".
I approach SQL queries like this from a programming perspective, as I feel the results tend to be less "magical". (A property I see in too many queries — it seems SQL queries these days are written using monkeys at keyboards…)
Figure out which company IDs we want to list. This is the union of these two things:
Any "people" results matched on name or number
Any "company" results matched on name or number
List out the number for that company, and the people as well.
Let's do #2 first:
SELECT
companyname AS name,
phone
FROM
customers
WHERE id IN (company_ids we want)
UNION
SELECT
name, phone
FROM
contacts
WHERE companyid IN (company_ids we want)
Since "company_ids we want" is going to be a query, rearrange this to boil it down to just 1 occurrence:
SELECT
name, phone
FROM
(
SELECT
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (company_ids we want)
Now, to fill in the fun part, we need to answer #1:
Part #1.1 is:
SELECT companyid FROM contacts WHERE name = $search OR number = $search;
Part #1.2 is:
SELECT id AS companyid FROM customers WHERE companyname = $search OR number = $search;
(Note that $search is our input — parameterized queries differ greatly from one SQL vendor to the next, so replace that syntax as needed.)
Put the UNION of those two in the IN, and we're done:
SELECT
name, phone
FROM
(
SELECT
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (
SELECT companyid FROM contacts WHERE name = $search OR phone = $search
UNION
SELECT id AS companyid FROM customers WHERE companyname = $search OR phone = $search
)
;
And pray the database can figure out a query plan that performs this in a reasonable amount of time. Sure you don't want to roundtrip to the DB a few times?
Note the methodology: We determined what we wanted ("the names/phones for customers/contacts matching certain companyids") and then figured out the missing piece ("which company ids?"). This comes from the fact that once you match a particular person in a company (say, sam), you want everyone from that company, plus the company, or everything with that company ID. Knowing that, we get our outer query (#2), and then we just need to figure out how to determine which companies we're interested in.
Note that these won't (and SQL queries, without an ORDER BY don't) give the queries back in your rather fancy order. You can add a helper column to the inner query, however, and accomplish this:
SELECT
name, phone
FROM
(
SELECT
0 AS is_person,
id AS companyid,
companyname AS name,
phone
FROM
customers
UNION
SELECT 1 AS is_person, companyid, name, phone FROM contacts
) AS entities
WHERE
companyid IN (
SELECT companyid FROM contacts WHERE name = $search OR phone = $search
UNION
SELECT id AS companyid FROM customers WHERE companyname = $search OR phone = $search
)
ORDER BY
companyid, is_person, name
;
You can also use the is_person column (if you add it to the SELECT) if you need to segment the results in whatever gets this query's results.
(And if you end up using queries of this length, please, for the love of God, -- comment them!)

Related

MySql: How to display only 1 name only per multiple name

To make it more clear, If I have this data in MySql:
name | allowance | age
----------------------
khan | 50 | 20
aal | 60 | 22
hyme | 50 | 21
khan | 61 | 20
notice that there are two 'khan' in the database with different allowance. I want to only show the name and the age but if I show it using the mysqli select statement, there would be two 'khan' but I only want to show only 1 'khan'. How can I do it?
You need to use GROUP_CONCAT to see agges of all Khans;
select name, GROUP_CONCAT(age) ages from Table group by name
or for minimum aged khan
select name , min(age) MiniumAge from Table group by name
or for elder khan
select name , max(age) MaxAge from Table group by name
or any khan
select name , age from Table group by name
.
Please try below query:-
SELECT name, age FROM table_name WHERE group by name
If you want any from multiple same record then simply used group by query.
I think you could do this:
SELECT name, age FROM table_name WHERE group by name,age
First thing: if both those "khan"s are the same person with two different allowances then your schema is not properly normalized and it will give you big troubles later - imagine you want to change "khan" to "Khan" - now you have to update it in multiple places instead once. Depending on your actual needs you may want one table of people (person_id, name, age), and table of allowances (person_id, allowance, [..some other parameters?..]).
Second, to really get what you want, either you use group by, to get one "random" row per each name as suggested in other answers, or you can do
SELECT DISTINCT name, age FROM table;
which will give you one row per each name-age combination, so khan-20 will be there only once - but if there were khan-25 then that is probably different person and you would have two khans returned, each with their own age.
You can try this mate:
SELECT DISTINCT
name, age
FROM
<your_table>;
or this one
SELECT
name, age
FROM
<your_table>
GROUP BY
name;
Q: Is there any chance that if there are 2 records of tha same name have difference value of age? If so, kindly update the question so that better answers will be given. Cheers!

How to correctly normalize data set in to tables?

I have a table where first column refers user name other columns refer each subjects that student does and their skill level for each subjects. These subjects are belong to several main subjects streams such as Mathematics, Art and etc.
I normalize the data in to following tables.
Subject_Stream
id Main_Stream Subject
1 Math pure-maths
2 Math applied-maths
3 Art Dancing
4 Art Music
Student_table
id name subject skill_level
1 xxx Music 5
2 xxx Pur-math 4
3 xxx Applied-math 1
4 yyy Music 3
select subjects, skill_level where usename="xxx" order by Desc
I can use a similar query to get subjects and their skill level for any given student.
Apart from, this I need to select students when I select any subject or collection of subjects that do.And print their Name, subjects, skill level in descending order.
Here any student can do different subjects in different streams too.
But I can't easily get this result from my existing tables. How to do this correctly?
Do I need to improve database schema?
First I want to suggest two small improvement for your table structure to better normalize the data. Your table Student_table would be slighly better organized if
instead of name you reference the user_id from your studends-table (that means the name of the student is only present in your studends-table - remember, names can change, p.e. marriage) and
instead of the name of the subject you reference the id of the subject - therefore the name of the subject is only present in your table Subject_Stream.
Your table Student_table would then look something like this:
id user_id subject_id skill_level
--------------------------------
1 1 4 5
2 1 1 4
3 1 2 1
4 2 4 3
Based on this you should be able to get every query you describe. For specifics please update your question and add some examples how your desired results look like, then I'll look into it and give you a few examples.
Apart from, this I need to select students when I select any subject
or collection of subjects that do. And print their Name, subjects,
skill level in descending order.
For a single subject . . .
select name, subject, skill_level
from Student_table
where subject = 'your subject name'
order by skill_level desc, name asc
For multiple subjects . . .
select name, subject, skill_level
from Student_table
where subject = 'some subject name'
or subject = 'some other subject name'
order by skill_level desc, name asc
There are other ways to express this kind of query, but I think multiple OR clauses is the easiest to understand at first.
To select by stream (Math, in this case) . . .
select Student_table.name
, Student_table.subject
, Student_table.skill_level
, subject_stream.main_stream
from Student_table
inner join subject_stream
on subject_stream.subject = student_table.subject
where subject_stream.main_stream = 'Math'
order by Student_table.skill_level desc, name asc

SQL Select statement from multiple tables while adding values

I'm having a bit of trouble figuring out a good statement to write. I am able to achieve what I want when I query a specific 'Company' but I wanting to get the values for all of the companies in the database.
Basically I have 3 tables: Users, Companies, Plans_ExchangeMailbox. What I need to do is query how many plans are in use for each company. The plans are assigned at the user level in the users table.
Here is my table layouts:
USERS
DisplayName
CompanyCode (This is the ID from the CompanyCode in the Companies table)
MailboxPlan (This is the ID from the Plans_ExchangeMailbox Table)
Companies
CompanyName
CompanyCode
Plans_ExchangeMailbox
MailboxPlanName
MailboxPlanID
Here is the format I am looking to generate:
CompanyName, MailboxPlanName, Count (this is the number of MailboxPlanID for a company)
I was able to get this working but the problem is it can only do one company at a time and it doesn't get the CompanyName:
SELECT
Plans_ExchangeMailbox.MailboxPlanName,
SUM(CASE WHEN Users.MailboxPlan = Plans_ExchangeMailbox.MailboxPlanId THEN 1 ELSE 0 END) AS PlanCount
FROM
Plans_ExchangeMailbox, Users
WHERE
Users.CompanyCode='CC0'
GROUP BY
Plans_ExchangeMailbox.MailboxPlanName
The Final Format How it Should Be:
Headers: CompanyName, PlanName, Count
Values:
Microsoft, Bronze Plan, 5
Microsoft, Gold Plan, 20
Dell, Bronze Plan, 3
Dell, Silver Plan, 80
etc.....
Try this:
SELECT
C.CompanyName,
E.MailboxPlanName,
COUNT(1) Cnt
FROM Companies C
JOIN Users U
ON C.CompanyCode = U.CompanyCode
JOIN Plans_ExchangeMailbox E
ON U.MailboxPlan = E.MailboxPlanID
GROUP BY
C.CompanyCode,
C.CompanyName,
E.MailboxPlanID,
E.MailboxPlanName
Grouped by C.CompanyCode and E.MailboxPlanID in case if there are different companies or MailboxPlan with same name. If no,you can remove them from GROUP BY clause.

Grouping Mysql query contacts table by city

an easy one, its long time i do not use mysql queries so maybe someone can help me out with this nooby question, i have a contacts table, id, name, and city.. i want to get all the contacts listed as follows.
city 1
--------
contact1
contact2
contact3
city 2
--------
contact4
contact7
contact10
city 3
--------
contact5
contact6
contact8
I do not want to use any additional php coding, just get the sql result like this
city 1
-> contact 1
-> contact 2
-> contact 3
city 2
-> contact 4
-> contact 7
-> contact 10
...
then fill the result in a php object and do like this:
foreach (cities as city)
{
// code here
}
Thanks in advance
Use GROUP_CONCAT
SELECT city, GROUP_CONCAT(name)
FROM contacts
GROUP BY city
You just need to GROUP BY city column and use GROUP_CONCAT function in SELECT to get comma seprated list of names for each city.
SELECT city, GROUP_CONCAT(name) AS name
FROM contacts
GROUP BY city;

MySQL - Select specific rows from multiple tables

I have a set of database tables named like:
site_1_details
site_2_details
site_3_details
...
site_420_details
all tables have the same fields, like:
ID | SETTING | VALUE
----------------------
1 name Site 1 Name
2 desc Site 1 Desc
3 email Site 1 Email...
...
(only the value fields are different)
How can I get a set of values from certain tables?
For example, I want to get the name & email values from sites 3,7 and 15. How could I do that with a SQL query?
SELECT 3 AS siteID, name, email
FROM site_3_details
UNION
SELECT 7 AS siteID, name, email
FROM site_7_details
UNION
SELECT 15 AS siteID, name,email
FROM site_15_details
This is a horribly bad design. Why couldn't you put a "siteID" field into a single table, which'd reduce the query to:
SELECT name, email
FROM site_details
WHERE siteID IN (3,7,15);
comment followup:
Ah well, then you just modify the individual queries:
SELECT 7 AS siteID, ID as fieldID, name AS fieldName
FROM site_7_details WHERE SETTING IN ('name', 'email')
UNION
....
Any reason you've designed the tables like this? Sounds like you're trying to implement your own database on TOP of a database engine which is already perfectly suited to doing this kind of relational data handling.