Zip code filter per seller - mysql - php

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;

Related

How to display a MySQL Many to Many Relationship with PHP

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!

how to use codeigniter where in on comma seperated row values

I am using codeigniter for my project and implementing search. I want to filter users from users table with cars they own. Structure of this table is shown below
+-----+----------+---------------------+---------------+
| #id | username | cars | other_details |
+-----+----------+---------------------+---------------+
| 1 | MAC | Jaguar,Porche | -- |
| 2 | DEV | Porche,Ferrari,Ford | -- |
| 3 | MONICA | Ford,Audi | -- |
+-----+----------+---------------------+---------------+
On front end, I am selecting cars from checkboxes which are returning car array for find users who have these cars like ["Porche","Ferrari"]. I am not able to find solution for how to get users using codeigniter active records in model. Please help me find out how to get users/rows having cars available in array.
Thanks in advance.
Finally, I find answer.First I had implode array with comma(,) and then use sql query and regular expression for getting an answer like this;
$this->db->sql("select * from users where `cars` NOT REGEXP '$cars'");
This query give data according to my requirement.

MySQL statement pulling too many rows

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)
";

Most efficient JOIN query - MySQL

Below is a gross over simplification of 2 very large tables I'm working worth.
campaign table
| id | uid | name | contact | pin | icon |
| 1 | 7 | bob | ted | y6w | yuy |
| 2 | 7 | ned | joe | y6e | ygy |
| 3 | 6 | sam | jon | y6t | ouy |
records table
| id | uid | cid | fname | lname | address | city | phone |
| 1 | 7 | 1 | lars | jack | 13 main | lkjh | 55555 |
| 2 | 7 | 1 | rars | jock | 10 maun | oyjh | 55595 |
| 2 | 7 | 1 | ssrs | frck | 10 eaun | oyrh | 88595 |
The page loops thru the records table and prints the results to an HTML table. The existing code, for some reason, does a separate query for each record "select name from campaign where id = $res['cid']" I'd like to get rid of the second query and do a some kind of join but what is the most effective way to do it?
I need to
SELECT * FROM records
and also
SELECT name FROM campaigns WHERE campaigns.id = records.cid
in a single query.
How can I do this efficiently?
Simply join the two tables. You already have the required WHERE condition. Select all columns from one but only one column from the other. Like this:
SELECT records.*, campaigns.name
FROM records, campaigns
WHERE campaigns.id = records.cid
Note that a record row without matching campaign will get lost. To avoid that, rephrase your query like this:
SELECT records.*, campaigns.name
FROM records LEFT JOIN campaigns
ON campaigns.id = records.cid
Now you'll get NULL names instead of missing rows.
The "most efficient" part is where the answer becomes very tricky. Generally a great way to do this would be to simply write a query with a join on the two tables and happily skip away singing songs about kittens. However, it really depends on a lot more factors. how big are the tables, are they indexed nicely on the right columns for the query? When the query runs, how many records are generated? Are the results being ordered in the query?
This is where is starts being a little bit of an art over science. Have a look at the explain plan, understand what is happening, look for ways to make it more efficient or simpler. Sometimes running two subqueries in the from clause that will generate only a subset of data each is much more efficient than trying to join the entire tables and select data you need from there.
To answer this question in more detail, while hoping to be accurate for your particular case will need a LOT more information.
If I was to guess at some of these things in your database, I would suggest the following using a simple join if your tables are less than a few million rows and your database performance is decent. If you are re-running the EXACT query multiple times, even a slow query can be cached by MySQL VERY nicely, so look at that as well. I have an application running on a terribly specc'ed machine, where I wrote a cron job that simply runs a few queries with new data that is loaded overnight and all my users think the queries are instant as I make sure that they are cached. Sometimes it is the little tricks that really pay off.
Lastly, if you are actually just starting out with SQL or aren't as familiar as you think you might eventually get - you might want to read this Q&A that I wrote which covers off a lot of basic to intermediate topcs on queries, such as joins, subqueries, aggregate queries and basically a lot more stuff that is worth knowing.
You can use this query
SELECT records.*, campaigns.name
FROM records, campaigns
WHERE campaigns.id = records.cid
But, it's much better to use INNER JOIN (the new ANSI standard, ANSI-92) because it's more readable and you can easily replace INNER with LEFT or other types of join.
SELECT records.*, campaigns.name
FROM records INNER JOIN campaigns
ON campaigns.id = records.cid
More explanation here:
SQL Inner Join. ON condition vs WHERE clause
INNER JOIN ON vs WHERE clause
SELECT *
FROM records
LEFT JOIN campaigns
on records.cid = campaigns.id;
Using a left join instead of inner join guarantees that you will still list every records entry.

mysql select query problem

i have a form that has a multiple select drop down. a user can select more than one options in the select. the name of the select is array[]; using php I call implode(",",$array)
in mysql db, it stores the field as a text in this format "places"= "new york, toronto, london" when i want to display these fields i explode the commas.
I am trying to run a report to display the places. here is my select:
"select * from mytable where db.places .. userSelectedPlaces"
how can i check toronto in lists of "places" that user selected? note "places" in the db might be either just "toronto" or it might be comma separated lists of places like "ny, toronto, london, paris, etc".
If it is possible, you would be much better off using another table to hold the places that the user has selected. Call it SelectedPlaces with columns:
mytable_id - To join back to the table in your query
place - EG: "Toronto"
Then you can run a simple query to figure out if Toronto has been selected:
SELECT *
FROM mytable m
INNER JOIN SelectedPlaces sp ON sp.mytable_id = m.id
WHERE sp.place = 'Toronto'
If I understand you correctly, your database design is just wrong. Try reading about it more. Generally, in good design you should not have lists of values as one field in database and you should introduce new table for it.
But if you want to do it this way, you can use strcmp function.
If i understood correctly, this should work:
WHERE DB.PLACES LIKE '%TORONTO%'
but as other users said, its not a nice thing to have denormalized tables.
To directly answer your question, your query needs to look something like this
SELECT *
FROM mytable
WHERE places LIKE( '%toronto%' )
But, be aware, that LIKE() is slow.
To indirectly answer your question, your database schema is all wrong. That is not the right way to do a M:N (many-to-many) relationship.
Imagine instead you had this
mytable place mytable_place
+------------+ +----------+----------+ +------------+----------+
| mytable_id | | place_id | name | | mytable_id | place_id |
+------------+ +----------+----------+ +------------+----------+
| 1 | | 1 | new york | | 1 | 1 |
| 2 | | 2 | toronto | | 1 | 2 |
| 3 | | 3 | london | | 1 | 3 |
+------------+ +----------+----------+ | 2 | 2 |
| 3 | 1 |
| 3 | 3 |
+------------+----------+
The table mytable_places is what's called a lookup table (or, xref/cross-reference table, or correlation table). Its only job is to keep track of which mytable records have which place records, and vice versa.
From this example we can see that The 1st mytable record has all 3 places, the 2nd has only toronto, and the 3rd has new york and london.
This opens you up too all sorts of queries that would be difficult, expensive, or impossible with your current design.
Want to know how many mytable records have toronto? No problem
SELECT COUNT(*)
FROM mytable_place x
LEFT JOIN place p
ON p.place_id = x.place_id
WHERE p.name = 'toronto';
How about the number of mytable records per place, sorted?
SELECT p.name
, COUNT(*) as `count`
FROM mytable_place x
LEFT JOIN place p
ON p.place_id = x.place_id
GROUP BY p.place_id
ORDER BY `count` DESC, p.name ASC
And these are going to be much faster than any query using LIKE since they can use indexes on columns such as place.name.

Categories