Is is possible to create the following dynaic SQL query in MySQL? - mysql

Given this sells table (in MySQL):
id | person | state | amount
1 | Ringo | CA | 3$
2 | Paul | CA | 10$
3 | John | MA | 2$
4 | Ringo | CA | 6%
5 | Ringo | MA | 12$
We like to create an SQL to get, for each person, what was his latest amount he sold in each state - something like that:
person | CA | MA
Ringo | 6$ | 12$
Paul | 10$| -
John | - | 2$
We also like this query to be dynamic enough, so if there will be a new record with a new state (e.g. TX), we will get it automatically.
6 | George | TX | 15$
Will result in:
person | CA | MA | TX
Ringo | 6$ | 12$ | -
Paul | 10$| - | -
John | - | 2$ | -
George| - | - | 15$
We tried Group by with this query:
select * from sells where id in(
select max(id) from sells
group by person, state
)
That seems to bring the right data for our needs, but we need help to do the extra leap to our wanted result

You may be able to get all the data you need with simpler SQL and format further in your application code to get the format that you want.
Table where for there is one row for each state a person has spent on:
id | person | state | amount
4 | Ringo | CA | 6$
5 | Ringo | MA | 12$
2 | Paul | CA | 10$
3 | John | MA | 2$
SQL query:
SELECT id, person, state, amount
FROM sells
GROUP BY person, state
HAVING id = MAX(id)

Related

MySQL return 0 if table doesn't have specific entry

Wasn't sure how to word my question, so sorry if it's a little confusing. Hopefully the below will clear it up a bit.
Here's the query I'm running so far:
select business.name, ifnull(sum(checkin.count),0) as checknum from checkin inner join business on business.id = checkin.business_id where business.state = 'NY' group by business.name order by checknum desc;
and it almost works as intended. There is one more business in NY, which doesn't have any counts in the checkin table, but I can't get it to output.
This is my current output:
+---------------------------------------+----------+
| name | checknum |
+---------------------------------------+----------+
| Lakeside Coffee | 31 |
| McDonalds | 18 |
| Valero | 15 |
| Angelo's Pizza & Grill | 13 |
| Gino's Pizza | 8 |
| Sandy's Deli | 7 |
| Tribeca North Luxury Apartments Homes | 2 |
| Matt & Nat | 2 |
| Filion's Diner | 2 |
| Squirrel's Nest Restaurant and Bar | 2 |
| Best Friends Family Diner | 1 |
| China Buffet | 1 |
| Sandi's Kountry Kitchen | 1 |
| Dick's Country Store | 1 |
+---------------------------------------+----------+
But I need to capture the last business that doesn't have any checkins. Not sure how to tackle this further.
You need to use right join instead of inner join.
Left join will return all rows on the right side of the relationship regardless of whether any key on the left side matches.

How to insert counts of rows by joining 3 tables on sql?

I am trying to join 3 tables and get counts of each contact's cases. So far I have this query written, but the result shows me contacts who has cases. I'd like to have a new column where it would show me "No of cases" for each contact, so the result should be 3 rows, 3 columns (last column is counts of cases)
Table A (Contacts)
+-----------------------+----+---------------------------------+
| Name | id | Organization |
+-----------------------+----+---------------------------------+
| Heidi Wilson-Reynolds | 2 | Alabama Arts Services |
+-----------------------+----+---------------------------------+
| Dr. Andrew Zope | 3 | Connecticut Empowerment Academy |
+-----------------------+----+---------------------------------+
| Rolando Cooper Sr. | 8 | Dutton Advocacy Trust |
+-----------------------+----+---------------------------------+
Table B (Case Contacts)
+----+---------+------------+
| id | case_id | contact_id |
+----+---------+------------+
| 1 | 1 | 2 |
+----+---------+------------+
| 2 | 2 | 3 |
+----+---------+------------+
| 3 | 3 | 8 |
+----+---------+------------+
| 4 | 4 | 2 |
+----+---------+------------+
| 5 | 5 | 3 |
+----+---------+------------+
| 6 | 6 | 8 |
+----+---------+------------+
Table C (Cases)
+----+-----------+
| id | status_id |
+----+-----------+
| 1 | 1 |
+----+-----------+
| 2 | 1 |
+----+-----------+
| 3 | 1 |
+----+-----------+
| 4 | 1 |
+----+-----------+
| 5 | 1 |
+----+-----------+
| 6 | 1 |
+----+-----------+
Query:
SELECT
A.display_name AS 'Name',
A.organization_name AS 'Organization'
FROM
A
INNER JOIN
B ON A.id = B.contact_id
INNER JOIN
C ON B.case_id = C.id
WHERE
A.contact_type = 'Individual' and C.status_id = 1; # Case status 1 is "Ongoing"
Result:
+-----------------------+---------------------------------+
| Name | Organization |
+-----------------------+---------------------------------+
| Heidi Wilson-Reynolds | Alabama Arts Services |
+-----------------------+---------------------------------+
| Dr. Andrew Zope | Connecticut Empowerment Academy |
+-----------------------+---------------------------------+
| Rolando Cooper Sr. | Dutton Advocacy Trust |
+-----------------------+---------------------------------+
| Heidi Wilson-Reynolds | Alabama Arts Services |
+-----------------------+---------------------------------+
| Dr. Andrew Zope | Connecticut Empowerment Academy |
+-----------------------+---------------------------------+
| Rolando Cooper Sr. | Dutton Advocacy Trust |
+-----------------------+---------------------------------+
This is the result I would like it to show, I think I need to use COUNT() function:
+-----------------------+---------------------------------+-----------------+
| Name | Organization | number_of_cases |
+-----------------------+---------------------------------+-----------------+
| Heidi Wilson-Reynolds | Alabama Arts Services | 2 |
+-----------------------+---------------------------------+-----------------+
| Dr. Andrew Zope | Connecticut Empowerment Academy | 2 |
+-----------------------+---------------------------------+-----------------+
| Rolando Cooper Sr. | Dutton Advocacy Trust | 2 |
+-----------------------+---------------------------------+-----------------+
Use group by
SELECT
A.display_name AS 'Name',
A.organization_name AS 'Organization',
count(*) AS 'number_of_cases'
FROM
A
INNER JOIN
B ON A.id = B.contact_id
INNER JOIN
C ON B.case_id = C.id
WHERE
A.contact_type = 'Individual' and C.status_id = 1; # Case status 1 is "Ongoing"
GROUP BY A.display_name, A.organization_name
The count(*) count the number of row that match the same value for the grouped by column .. in your case you have three distinct value for (name, Organization)
the the group by clause return this three different rows .. ad for each of this row count the number of rows that have the same value for name and Organization.
In you sample all the three value for (name, Organization) have 2 rows each ..
see this for brief tutorial for aggregation function
http://www.w3schools.com/sql/sql_functions.asp
http://www.sql-tutorial.com/sql-aggregate-functions-sql-tutorial/
Use GROUP BY NAME, ORGANIZATION and count the results using the output of this query. Basically you can include this output in another SELECT statement to get desired result

How to select / join some data from one mySQL innodb table to another with no duplicates and choosing the last inserted row per id

I'm new to mySQL, and I'm trying to be able to either SELECT or CREATE A VIEW with the information I want to retrieve from two tables. SQLfiddle
People Table
| people_id | username | Password | Email |
----------------------------------------------
| 1 | username1 | Password1 | Email1 |
| 2 | username2 | Password2 | Email2 |
| 3 | username3 | Password3 | Email3 |
Profile Table
| people_id | id | age | location | hobbies | about |
----------------------------------------------------------------------------------------------------------------------------
| 1 | 1 | 22 | USA | skiing, snowboarding | I am from the US and I like to snowboard |
| 2 | 2 | 45 | Canada | curling, ice skating, reading | I like to ice skate! |
| 3 | 3 | 38 | USA | tv, movies, you name it | I am from the US and I like to watch the tube |
| 2 | 4 | 45 | Canada | curling, reading | I do not like to ice skate anymore |
| 2 | 5 | 46 | Canada | bowling | Bowling is my new favorite hobby! I just turned 46! |
| 1 | 6 | 22 | Brazil | skiing, snowboarding | I am orginally from the US but I just moved to brazil|
I would like to see/retrieve the data like this :
| people_id | username | age | location | hobbies | about |
------------------------------------------------------------------------------------------------------------------------------------
| 3 | username3 | 38 | USA | tv, movies, you name it | I am from the US and I like to watch the tube |
| 2 | username2 | 46 | Canada | bowling | Bowling is my new favorite hobby! I just turned 46! |
| 1 | username1 | 22 | Brazil | skiing, snowboarding | I am orginally from the US but I just moved to brazil|
So I need to select all the people_id and username from table People and then select the people_id row from Profile where the id is the largest number for each people_id
I've tried
SELECT People.people_id, People.username, Profile.age, Profile.location, Profile.hobbies, Profile.about
FROM People
INNER JOIN Profile
ON People.people_id=Profile.people_id
Which gets me closer to what I want, but I don't want to show duplicate rows, I only want to show the last row inserted into the Profile table for each people_id.
SQLfiddle
The most efficient way to get what you want is to use a not exists condition in the where clause. This definitely takes some getting used to. What the query is going to do is to get the matching row from Profile subject to the condition that no other row has a larger id. This is a round-about way of saying "get the biggest id for each person". But, it happens to produce an efficient query plan (and this is true in most databases, not just MySQL).
SELECT p.people_id, p.username, pr.age, pr.location, pr.hobbies, pr.about
FROM People p INNER JOIN
Profile pr
ON p.people_id = pr.people_id
WHERE NOT EXISTS (SELECT 1
FROM Profile pr2
WHERE pr2.people_id = pr.people_id AND
pr2.id > pr.id
);
SELECT People.people_id, People.username, Profile.age, Profile.location, Profile.hobbies, Profile.about
FROM People
INNER JOIN (SELECT * FROM Profile ORDER BY id DESC) AS Profile
ON People.people_id=Profile.people_id
GROUP BY People.people_id
ORDER BY people_id DESC

Assistance with database design

I've got a excel sheet that contains all the employees that have worked for my company and is still working for us. It's a sheet of around 200 rows. Each row has basic info, like surname, name, position, qualification etc etc. 16 columns of basic info. Now, the tricky part is this. After the 16 columns, there are months (May-05 up to the present (Apr-12)). Under every month column, an employee either get's a 0 (contract), 1 (permanent), 2 (contract-terminated) or 3 (student).
What would be the best way to do this? I was thinking of 4 tables (listed below), where the one table determines permanently terminated people (for the sake of knowing who was on what type of employment).
MySQL Table: hr_employees
|-----------------|-------|----|----|----|
| employee_number | name | sur| etc| etc|
|-----------------|-------|----|----|----|
| 1 | Dave | F | xx | xx |
|-----------------|-------|----|----|----|
MySQL Table: hr_month
|----|--------|
| id | month |
|----|--------|
| 1 | May-05 |
| 2 | Jun-05 |
|----|--------|
MySQL Table: hr_status
|----|------|------|--------|
| id | e_no | date | status |
|----|------|------|--------|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
|----|------|------|--------|
MySQL Table: hr_terminated
|----|------|
| id | e_no |
|----|------|
| 1 | 1 |
| 2 | 1 |
|----|------|
I hope you guys understand what I want to achieve, otherwise, ask a question, and I'll answer as best I can! :)
Thanks.
Here is a design that simplifies your data entry and is more relational database like and less Excel like, insofar as it's normalized.
MySQL Table: hr_employee
|-----------------|-------|----|----|----|
| employee_number | name | sur| etc| etc|
|-----------------|-------|----|----|----|
| 1 | Dave | F | xx | xx |
|-----------------|-------|----|----|----|
| 2 | Bob | M | xx | xx |
|-----------------|-------|----|----|----|
MySQL Table: hr_employee_status
|-----------------|------------|------------|--------|
| employee_number | from_date | to_date | status |
|-----------------|------------|------------|--------|
| 1 | 2005-05-01 | 2005-08-31 | 3 |
|-----------------|------------|------------|--------|
| 1 | 2006-05-01 | 2010-02-28 | 0 |
|-----------------|------------|------------|--------|
| 2 | 2010-03-01 | 9999-12-31 | 1 |
|-----------------|------------|------------|--------|
Here you can see that Dave was hired on as a student from May '05 to August '05, then he came back in May '06 as a contract employee which he worked as until the end of February '10. Then on March 1, 2010 Bob was hired as permanent employee and he is still working (max collating date means "until further notice").
The great advantage of this design is that you only have to enter/edit data when something changes, not once a month for every employee that you have or have ever had. You can also see what your workforce looked like at any given date (not just by months!) with a very simple SQL query.

Join only for specific rows where value matches a variable

I have multiple MySQL tables containing varying numbers of columns. After joining three of the tables, I have a resulting table that's structured as follows:
+------------+------------+-----------+-------+------+
| student_id | first_name | last_name | class | rank |
+------------+------------+-----------+-------+------+
| 1 | John | Doe | 2012 | 1 |
+------------+------------+-----------+-------+------+
| 2 | Suzy | Public | 2013 | 12 |
+------------+------------+-----------+-------+------+
| 3 | Mike | Smith | 2014 | 50 |
+------------+------------+-----------+-------+------+
I also have two additional tables that aren't involved in the initial join:
interest
+-------------+------------+-----------------------+----------------+
| interest_id | student_id | employer_interest | interest_level |
+-------------+------------+-----------------------+----------------+
| 1 | 1 | Wayne Enterprises | High |
+-------------+------------+-----------------------+----------------+
| 2 | 1 | Gotham National Bank | Medium |
+-------------+------------+-----------------------+----------------+
| 3 | 2 | Wayne Enterprises | Low |
+-------------+------------+-----------------------+----------------+
| 4 | 3 | Gotham National Bank | High |
+-------------+------------+-----------------------+----------------+
offers
+----------+------------+-----------------------+
| offer_id | student_id | employer_offer |
+----------+------------+-----------------------+
| 1 | 1 | Wayne Enterprises |
+----------+------------+-----------------------+
| 2 | 1 | Gotham National Bank |
+----------+------------+-----------------------+
| 3 | 2 | Wayne Enterprises |
+----------+------------+-----------------------+
The interest and offers table won't necessarily contain a record for every student_id but at the same time contain multiple records that reference a single student_id.
For each of the latter two tables, I'd like to:
Select all rows where the employer_interest or employer_offer value is equal to $var (a variable I've set in PHP)
Join these rows to the original table
For example, if $var is set to Wayne Enterprises, I'd like the resulting table to be:
+------------+------------+-----------+-------+------+-------------------+----------------+-------------------+
| student_id | first_name | last_name | class | rank | employer_interest | interest_level | employer_offer |
+------------+------------+-----------+-------+------+-------------------+----------------+-------------------+
| 1 | John | Doe | 2012 | 1 | Wayne Enterprises | High | Wayne Enterprises |
+------------+------------+-----------+-------+------+-------------------+----------------+-------------------+
| 2 | Suzy | Public | 2013 | 12 | Wayne Enterprises | Low | Wayne Enterprises |
+------------+------------+-----------+-------+------+-------------------+----------------+-------------------+
| 3 | Mike | Smith | 2014 | 50 | NULL | NULL | NULL |
+------------+------------+-----------+-------+------+-------------------+----------------+-------------------+
Is what I'm trying to do possible using just a MySQL query? If so, how do I do it?
it sounds like you just need a LEFT JOIN to the other tables since it appears you want to see all students from the first set regardless of any job offer/interest.
If so... ensure both the "Interest" and "Offers" tables have an index where the student ID is either a single element index, or first in that of a compound index.
select STRAIGHT_JOIN
ORS.Student_ID,
ORS.First_Name,
ORS.Last_Name,
ORS.Class,
ORS.Rank,
JI.Employer_Interest,
JI.Interest,
OFR.Employer_Offer
from
OriginalResultSet ORS
LEFT JOIN Interest JI
ON ORS.Student_ID = JI.Student_ID
AND JI.Employer_Interest = YourPHPVariable
LEFT JOIN Offers OFR
on JI.Student_ID = OFR.Student_ID
AND JI.Employer_Interest = OFR.Employer_Offer
To prevent "NULL" results in the employer interest, interest and offer, you can wrap them in a Coalesce() call such as (for all three columns on left join)
COALESCE( JI.Employer_Interest, " " ) Employer_Interest
Your query should be something like this:
select
s.student_id, s.first_name, s.last_name, s.class, s.rank,
i.employer_interest, i.interest_level,
o.employer_offer
from students s
left join interest i
on i.student_id = s.student_id
and i.employer_interest = 'Wayne Enterprises'
left join offers o
on o.student_id = s.student_id
and o.employer_offer = 'Wayne Enterprises'