SQL Multiple queries of WHERE + AND from two columns - mysql

I have a database of orders that looks roughly like this
ORDER ID | AMOUNT | FIRSTNAME | LASTNAME
1 50 JOHN SMITH
2 60 PAUL JOHNSON
3 20 FRANK CAMERON
5 80 JOHN JOHNSON
I have a list of names that I need to pull their orders. For this example lets say "JOHN SMITH" and "PAUL JOHNSON"
I have tried a query like this
SELECT * FROM ORDERS WHERE FIRSTNAME IN ("JOHN", "PAUL") AND LASTNAME IN ("SMITH", "JOHNSON")
But obviously that didn't work how I wanted as it included. I'm not sure how to go about it but I need to search something like
WHERE FIRSTNAME,LASTNAME IN ("JOHN","SMITH";"PAUL","JOHNSON")
OR
WHERE (FIRSTNAME,LASTNAME) IN {("JOHN","SMITH")("PAUL","JOHNSON")}
Obviously I know little about SQL so I'm getting stuck on syntax and terminology of what to search for?

You can separate the logic with an OR like this:
SELECT * FROM ORDERS
WHERE
(FIRSTNAME = "JOHN" AND LASTNAME = "SMITH")
OR
(FIRSTNAME = "PAUL" AND LASTNAME = "JOHNSON")

You could do something like this
SELECT *
FROM ORDERS
WHERE concat(firstname, ' ', lastname) IN ('JOHN SMITH','PAUL JOHNSON')

Related

Binding results of two SQL queries by column

I have tried a lot of searching online and unable to find an answer to this. As an example, lets say I have two tables, Persons and Names with the following info (this is only for illustration and I don't have control over the DB structure)
Persons:
PID FNameID LNameID
1 100 101
2 102 103
3 100 103
...
Names:
NameID Name
100 James
101 Baker
102 Thomas
103 Walter
Is there a simple query to obtain the following result, for a given person (PID) the first and last names and then combine them to display like:
PID FName LName
1 James Baker
I looked at UNION, JOIN, nested queries, etc but couldn't figure it out. Feel like I'm missing something basic. Any help is appreciated.
Wanted to add that I am able to get each name separately and combine with PHP, but I was hoping there was a Sql way of doing it (like UNION does it for row binding)
You need two joins:
select p.pid, nf.name as fname, nl.name as lname
from persons p left join
names nf
on p.fnameid = nf.nameid left join
names nl
on p.lnameid = nl.nameid;
Try this
SELECT
p.PID, fname.Name as FName, lname.Name as LName
FROM Persons p
JOIN Name fname ON p.FNameId=fname.Id
JOIN Name lname ON p.LNameId=lname.Id
WHERE p.PID=1;
More about JOIN https://dev.mysql.com/doc/refman/8.0/en/join.html

SQL query to get number of times a field repeats for another specific field

Let's say I have two fields in a table. For the purpose of discussion let's say the fields are first name and last name. I want to know how many times the first name shows up listed next to the same last name. Assuming the last name column is unique, how do I figure out how many times each first name exists for each last name?
i.e. let's say I have a table with the following data:
Smith, John
Smith, David
Smith, Jane
Smith, John
Smith, John
Black, John
Black, Jane
Black, Jack
Black, Samantha
Black, Jack
I want a result that tells me that for Smith, there are 3 Johns, 1 David and 1 Jane, and for Black, there are 2 Jacks, 1 Jane and 1 Samantha.
Not sure how to format the output best. Maybe simply:
Smith, John, 3, David, 1, Jane, 1
Black, Jack, 2, Jane, 1, Samantha, 1
Something that would allow me to easily output something like:
Smith: John (3), David (1), Jane (1)
Black: Jack (2), Jane (1), Samantha (1)
It's important to note that it's possible that the second field can repeat, so counting unique instances in the column is not useful. It's only useful in reference to the first field.
Thanks.
You can use a correlated sub-query in your SELECT statement and then wrap it all in a concat function to get the inline result you wanted
SELECT DISTINCT
CONCAT(LastName, ': ', FirstName, '(', (SELECT COUNT(FirstName) FROM Person WHERE FirstName = p.FirstName AND LastName = p.LastName),')')
FROM Person p
Simple aggregation?
select last_name, first_name, count(*)
from myTable
group by last_name, first_name
order by last_name, first_name
Displaying it in a Smith, John, 3, David, 1, Jane, 1 format will probably fail because there are way too many Smiths with way too many different last names.
My solution:
select name,surname, count(surname) over (partition by name) as cnt
from your_table
You can use this.
SELECT CONCAT( Name,':', GROUP_CONCAT(CONCAT( LastName, ' (', CNT , ')' ), ' ') )
FROM (
SELECT Name, LastName, COUNT(*) CNT FROM MyTable
GROUP BY
Name, LastName
) T
GROUP BY Name
Sql Fiddle
Result:
Black:Jane (1) ,John (1) ,Samantha (1) ,Jack (2)
Smith:David (1) ,Jane (1) ,John (3)

SQL Return value based on lowest value in another column

I've tried to search for a solution to this but have been unable to find one. I guess it's basic SQL, but I can't seem to figure it out.
I have a table called people, this table has several columns:
ID Firstname Lastname Birthdate
1 John Stevenson 1860-07-30
2 Eric Johnson 1918-08-25
3 Adam Efron 1914-02-02
4 Michael Gray 1870-07-18
Now I want to make a query that looks at the Birthdate column, finds the lowest value and returns the firstname of the person that has the lowest birthdate (is oldest).
Can someone guide me in the right direction?
THanks in advance!
Use order by like
select Firstname
from people
order by Birthdate
limit 1
This will account for 2 paople having the same birthdate, returning 2 rows.
select Firstname
from people
where birthdate = (select min(birthdate) from people);
Another way to do it efficiently would be this (sqlfiddle):
select p.*, min(p.birthdate) from people p;
NOTE: You will have 1 extra column in the output.

How to select every row N times in MySql table?

I have a MySQL table like below.
ID NAME SURNAME
1 Joe Black
2 Mary Peterson
3 Bob Marley
4 Andy Murray
...
I want to write a SELECT command which will return every row N times.
Example for N = 3.
SELECT NAME, SURNAME blah-blah (3 Times ) FROM Person
NAME SURNAME
Joe Black
Joe Black
Joe Black
Mary Peterson
Mary Peterson
Mary Peterson
Bob Marley
Bob Marley
Bob Marley
Andy Murray
Andy Murray
Thank you.
You could use UNION ALL to get the result you want, but you'd better not do such job with SQL.
SELECT * FROM
(
SELECT NAME, SURNAME FROM Person
UNION ALL
SELECT NAME, SURNAME FROM Person
UNION ALL
SELECT NAME, SURNAME FROM Person
) A ORDER BY NAME
I won't suggest sql to achieve this, a much simpler way would be (assuming PHP) :
$result = $mysqli->query("SELECT NAME, SURNAME blah-blah (3 Times ) FROM Person");
while($result_set = $result->fetch_array())
{
for($i=0;$i<4;$i++)
{
echo $result_set['name']." ".$result_set['sur_name']."\n";
}
}
This would give you a better control on the result set as well as, you can have more dynamic ways of handling, how the data is displayed on the page,
for. eg, if u want a particular name to be printed only once, a simple if comparison would do, which is not possible via sql!!
SELECT NAME, SURNAME FROM Person, (SELECT * FROM Person limit 3) count_table;
The dumb manual way would be:
SELECT NAME, SURNAME FROM Person
UNION ALL
SELECT NAME, SURNAME FROM Person
UNION ALL
SELECT NAME, SURNAME FROM Person
Another way is to have a table with numbers in a single column running up to the maximum and doing a cross join with it WHERE number <= n
what about go through looping it in stored procedure like that :
delimiter //
CREATE PROCEDURE ntimes()
BEGIN
DECLARE i INT DEFAULT 0;
SET i = 0;
WHILE i < 3 DO
SELECT `Code`, `Rank` FROM Table1;
SET i = i + 1;
END WHILE;
END;
//
DELIMITER ;
Here you just change 3 to what number of repeats you want , and you dont need mass of unions .

mysql query two tables

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!)