I have two data tables that I am querying using an Inner Join statement. one of the tables pulls daily company stock information and consequently has a row for each company for each day the market is open. The other table holds qualitative data about the company and only has one row per company.
I am trying to pull the most recent stock information and pair it with the qualitative company information in an HTML table. I have everything working except that it is still pulling every row of daily info for the company rather than the most recent.
Can someone assist with this query?:
$query = "SELECT daily_info.Day,
daily_info.Prev_close,
stocks.Symbol,
stocks.Company,
stocks.Description
FROM daily_info
INNER JOIN stocks ON daily_info.Symbol = stocks.Symbol
ORDER BY daily_info.Day, stocks.Company LIMIT 43
";
Example:
Table 1: Daily_info
Day | Symbol | Company | Prev Close
06/15/14 | CRM | Salesforce | $52.34
06/15/14 | AMZN | Amazon | $342.65
06/16/15 | CRM | Salesforce | $55.24
06/16/14 | AMZN | Amazon | $349.64
Table 2: Stock
Symbol | Company | Description
CRM | Salesforce.com | This is a cloud based CRM company
AMZN | Amazon.com | This is an ecommerce company
Output:
Company | Symbol | Prev Close | Description
Amazon.com | AMZN | $349.64 | This is an ecommerce company
Salesforce.com | CRM | $55.24 | This is a cloud based CRM company
I don't think MySQL supports LAG functions so you'll need to do a subquery to get the last date for each Symbol, then INNER join on that result. Something like this should work:
$query = "
SELECT l.Company, l.Symbol, l.Prev_Close, r2.Description
FROM Daily_info as l
INNER JOIN
(SELECT Symbol, MAX(Prev_close) as last_date FROM Daily_info GROUP BY Symbol) AS r
ON (l.Symbol=r.Symbol AND l.Prev_close=r.last_date)
INNER JOIN Stock as r2
ON (l.Symbol=r2.Symbol)
";
Related
I am trying to display information on a website using PHP and MYSQL that shows all the locations an event can take place, along with the facilities each location includes. For example, a park (location1) may contain toilets (facility1), swings (facility3) and a slide (facility4).
Location1 Location2 Location3 Location4
Facility1 x x
Facility2 x x
Facility3 x x
Facility4 x x
Firstly, I am unsure of the best way to display these as tables in MySQL and then how I would display this clearly using PHP calls onto a webpage.
Any help would be appreciated
Database schema
I would like to recommend you to create 3 tables in your database:
locations
facilities
location_facility
Locations table
+----+------------+
| id | name |
+----+------------+
| 1 | location_1 |
| 2 | location_2 |
+----+------------+
Facilities table
+----+------------+
| id | name |
+----+------------+
| 1 | facility_1 |
| 2 | facility_2 |
| 3 | facility_3 |
+----+------------+
Pivot table (location_facility)
+-------------+-------------+
| location_id | facility_id |
+-------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 3 |
+-------------+-------------+
So, in pivot table you can store required information.
PHP application meta code
To get the data from your database in pure PHP - you can use PDO extension.
$sql = 'SELECT locations.name as loc_name,
facilities.name as facility_name
FROM location_facility
INNER JOIN locations ON locations.id = location_facility.location_id
INNER JOIN facilities ON facilities.id = location_facility.facility_id';
foreach ($conn->query($sql) as $row) {
print $row['loc_name'] . "\t";
print $row['facility_name'] . "\n";
}
In the database it is only one additional table, holding both PK from the related tables.
For display you'd choose a "master-detail" view: seleting one item from either table (master), showing all related records from the other (detail).
As others had commented, the tables required a third pivot table to connect the facilities and the location tables so many thanks for that. However, the next issue that arose was using these tables and connecting them to allow searches by facilities.
Hence an SQL query that grouped the facilities into one column within a view alongside all information from the location table.
CREATE VIEW locations AS
SELECT location.*, group_concat(facilities.FacilityName separator ',') AS facility_name
FROM location_facility
INNER JOIN location
ON location.LocationID = location_facility.LocationID
INNER JOIN facilities
ON facilities.FacilitiesID = location_facility.FacilitiesID
GROUP BY location.LocationName
ORDER BY location.LocationID ASC
This table can be queried using
SELECT *
FROM locations
WHERE facility_name LIKE %Toilet% AND facility_name LIKE %Parking%
This solved my issues and allowed the data to be displayed on a webpage exactly how I had desired.
Thanks again for the comments and help all!
I am implementing a web service in PHP that will retrieve a list of sellers who deliver at certain zip codes. I want to know any better approaches to do this than what I'm currently doing.
Sample table for zip codes (ziptable):
-----------------------
| seller_id | zipcode |
-----------------------
| 101 | 110012 |
-----------------------
| 101 | 110023 |
-----------------------
| 102 | 110023 |
-----------------------
Now I'm using the following query to get the list of sellers who deliver at zip code 110023:
SELECT * FROM sellers s, ziptable z
WHERE z.zipcode = 110023 AND s.id = z.seller_id ;
Are there any better approaches to get the same result either by changing database schema or SQL queries?
You don't actually need to return any columns from the zipcodes table, but apart from that, with appropriate indexes, this is just fine. Note that we would normally write that more like this:
SELECT s.*
FROM ziptable z
JOIN sellers s
ON z.seller_id = s.id
WHERE z.zipcode = 110023;
i have two tables 'reviews' and 'company'
//****Company****//
id | name | others |
1 | company 1 | dhvhvbd|
2 | company 2 | didhhdi|
3 | company 3 | fyfyufu|
4 | company 4 | hdihdhi|
//***Reviews****//
id | company_id | rate |
1 | 1 | 3 |
2 | 3 | 5 |
3 | 1 | 4 |
I am trying to write an SQL query like this (not correct but you should know what i want)
$query = "
SELECT c.id
, c.name
, c.others
, AVG(r.rate) rate
, COUNT(*) count
FROM company c
LEFT
JOIN reviews r
ON r.company_id = c.id
GROUP
BY c.id;
";
This might look messy but this is what i want: to display all this listed company (irrespective of if they have a review in the review table), also get the average of 'reviews.rate' for each company (as they will be more than 1 review for one company) also get the count of the review where the company appears.
example:
display
id | name | others | rate | count |
1 | company 1| dhvhvbd| 3.5 | 2 |
2 | company 2| didhhdi| NULL | NULL |
3 | company 3| fyfyufu| 5 | 1 |
4 | company 4| hdihdhi| NULL | NULl |
I hope its clear enough, i am just getting to learn some little bit complex queries
You need to add all columns into the group by clause that won't get aggregated with a function
SELECT company.id, company.name, company.others,
AVG(reviews.rate) AS rate,
COUNT(reviews.id) AS `count`
FROM company
LEFT JOIN reviews ON company.id = reviews.company_id
GROUP BY company.id, company.name, company.others
And if you have 2 tables with the same column names then you need to name the table too. You used group by id in your query but the DB does not know which one to take - from reviews or from company.
Since you're using aggregate operators like COUNT and AVG, you have to group your records, by company.id, company.name and company.others (all the columns included in the SELECT clause). For this reason your query won't work.
Furthermore, using GROUP BY id your MySQL engine will complain, because actually the column id is ambiguous, because both tables involved in the LEFT JOIN have an id column and the engine doesn't understand which column of which table you mean.
Use the following query:
SELECT company.id, company.name, company.others,
AVG(reviews.rate) AS rate,
(CASE WHEN COUNT(reviews.id) = 0 THEN NULL ELSE COUNT(reviews.id) END) AS `count`
FROM Company
LEFT JOIN Reviews ON company.id = reviews.company_id
GROUP BY company.id, company.name, company.others
See the SQL Fiddle here.
I have currently got a PHP generated calendar displaying some holidays for users. This information is stored in a database, I.e holidays and users. I want a user to be able to select a department and then AJAX will load the holidays for users only in that department.
Here are two made up tables with the same fundamental structure:
Table users
+------------------------------------+
| User | Department |
|------------+-----------------------|
| Brian | Sales |
| Tony | Marketing |
| Carol | Marketing |
| Dave | Warehouse |
| Chris | Warehouse |
+------------------------------------+
Table holiday
+------------------------------------+
| ID | User |
|------------+-----------------------|
| 1 | Dave |
| 2 | Tony |
| 3 | Tony |
| 4 | Chris |
| 5 | Carol |
+------------------------------------+
My current query:
$getAllHols = $con->query("SELECT * FROM `holiday`");
So of course, this just gets all holiday. I'm knowledgable enough on PHP to get a list of users in a specific department and then use that in another query to get holidays for those users. But I don't want to do this. I'm thinking there MUST be a pure-SQL solution. So I need the query to get all records from holiday where the user is in the selected department, using the two tables.
I.E:
If I chose the department "Marketing", records 2, 3 and 5 would be returned. (Tony and Carol are in Marketing).
Very easy problem for an advanced SQL user, I'm sure, but not to me. Can anyone help? Thanks.
Try this.
SELECT * FROM users
LEFT JOIN holiday ON users.user = holiday.user
WHERE holiday.department = 'marketing'
As far as I got...
select user
from users inner join holiday
on users.user = holiday.user
where department = 'Marketing'
This would provide a distinct list of records from the Holiday table if there are any matching records from the Users table. This improves upon the option of joining the tables, as you would not have to worry about de-duping the resulting data.
select distinct h.id, h.user
from holiday h
where h.user in (select u.user
from user u
where u.department = 'Marketing')
;
I work for a hosting company were we often get requests for installs, new domains, lag fixes etc. To get a bit of an overview of what is still open I decided to make a really simple ticket system. I have a bit of php knowledge and a bit of MySQL knowledge. For now we will be submitting the tickets ourselves based on e-mails and phonecalls from customers.
I have created the following SQL structure:
|| TICKETS || || STATUSSES || || STATUS-CODES ||
-------------- ---------------- -------------------
| ID | | ticket_id | | ID |
| cust_name | | status_id | | status_txt |
| cust_cntct | | datetime | -------------------
| subject | ----------------
| message |
--------------
I now want to make the overviw table showing all the existing tickets. A ticket is inserted with a default status. The concurring timestamp will be the time that the ticket was added. Every time a ticket moves to the next status a new status will be added with a timestamp. The newest status is always the current status.
I can't figure out how to create a query that will get every ticket with its latest status. A simple join will return a ticket as many times as the amount of statusses it has. I want to create a join but only show the results were the timestamp of the status is the newest for a certain ticket.
Try this:
SELECT a.*, b.`datettime`, d.status_txt
FROM tickets a
INNER JOIN statusses b
on a.id = b.ticket_ID
INNER JOIN
(
SELECT ticket_ID, MAX(`datetime`) CurrentTicketDate
FROM Statuses
GROUP BY ticket_ID
) c
ON b.ticket_ID = c.tecket_ID AND
b.`datetime` = c.CurrentTicketDate
INNER JOIN Status_Codes d
on b.status_ID = d.id