I have a table where i need to check or compare two rows two column are equal then only i need to retrieve data
my table structure is
id | route_id | stop_id | bus_id | bus_time | trip | direction
if i execute following query
select routes.route_name,stops.stop_name,buses.bus_name,bus_timings.bus_time,bus_timings.trip,bus_timings.bus_direction from `bus_timings`
inner join `stop_orders` on `stop_orders`.`id` = `bus_timings`.`stop_order_id`
inner join `routes` on `stop_orders`.`route_id` = `routes`.`id`
inner join `stops` on `stop_orders`.`stop_id` = `stops`.`id`
inner join `buses` on `buses`.`id` = `bus_timings`.`bus_id`
where `stops`.`stop_name` in ("sydney","melborne")
output
1 | route_1 | Sydney | bus_1 | 07:05 :00 | 1 |1
2 | route_1 | Melbourne| bus_2 | 07:35:00 |1 |1
but in existing query even if bus is not traveling between Sydney also i will get Melbourne result
.
I need to get only buses name which falls or travel between Sydney to Melbourne
simple way to do that , without much fuzz , and as u mentioned using PHP,
so use only one where clause in the query statement and than filter the data using php,
for example ,
after you retrieve the buses between Sydney and Melbourne, make a foreach loop and use if condition with selected times.
another way us that if you like using arrays
match the times in each record using any array search function and get the keys out to another array.
the result array will contain the filtered data with buses between cities and between selected time.
Related
purpose: I have been tasked with exporting a complex dataset from a PHP counseling appointment webapp, and convert it into an excel file containing student data sorted by their STUDENT_ID.
I have 3 MySQL tables containing data. They all have a STUDENT_ID field.
I need to make a query which retrieves all the data from the 4 tables, grouping into a single row based on STUDENT_ID.
Some of the tables contain multiple entries for the same STUDENT_ID. If possible I'd like these multiple entries combined into a single row (so that each unique STUDENT_ID is on one line).
This is what I have so far but it doesn't seem to work how I expect it to.
SELECT *
from ssp_student t1
INNER JOIN ssp_student_quarterly t2
ON t1.STUDENT_ID = t2.STUDENT_ID
INNER JOIN ssp_weekly_progress t3
ON t2.STUDENT_ID = t3.STUDENT_ID
GROUP BY t1.STUDENT_ID
Table Schema:
Table 1:
| STUDENT_ID | PEER_COACH_ID | ACTIVE | COHORT | WEEKLY_MEETING_TIME | FYE_ID | RC | AGREEMENT_SIGNED | RELEASE_SIGNED | NOTES | FACULTY_ADVISOR |
Table 2:
| STUDENT_ID | QUARTER | COUNSELLING_OFFICE | WRITING_CENTER | CASE_MANAGEMENT | SSP_SOCIAL_EVENTS | SSP_SUCCESS_SEMINAR | HOME_SUPPORT | ACCOMODATION_USED | DISCOVERY_PATHWAYS | PEER_COACHING |
Table 3:
| STUDENT_ID | QUARTER | WEEK | EMAIL_INTERACTION | PHONE_INTERACTION | TEXT_INTERACTION | INPERSON_INTERACTION | SOCIAL_INTERACTION | NUMBER_OF_SOCIAL_INTERACTIONS | CASE_MANAGEMENT_INTERACTIONS | NUMBER_OF_CASE_mANAGEMENT_INTERACTIONS | SUCCESS_SEMINAR_INTERACTION | NUMBER_OF_SUCCESS_SEMINAR_INTERACTIONS | OTHER_INTERACTION | THEMES | SURVEY_ID | NOTES |
what I need: I want 1 row for each STUDENT_ID, which contains columns for all the data associated with that STUDENT_ID in tables 1, 2 and 3.
if you use SELECT * and you say that some of the tables contain more than one row for the same student, you will never get only one row. Try to select the fields related to the student id that you want to display.
If any of the fields that you want to display is one of the multiple-entry, then it will not work, it will display one row per entry.
If you really want to concatenate the data for each row into one field, your SELECT statement you could do something like the following:
SELECT t1.STUDENT_ID, GROUP_CONCAT(t2.Field1 SEPARATOR ', ') AS t2Field1Concat,
GROUP_CONCAT(t2.Field2 SEPARATOR ', ') AS t2Field2Concat,
GROUP_CONCAT(t3.Field1 SEPARATOR ', ') AS t3Field1Concat,
GROUP_CONCAT(t3.Field2 SEPARATOR ', ') AS t3Field2Concat
In the above example you would have to do this for each field other than t1.STUDENT_ID.
You seem to be after 4 separate groups of data that have virtually nothing in common other than the student ID. You should perform a single query for each and then combine the data into a relevant format in PHP.
Joining all 4 tables together like this is going to end up with a potentially MASSIVE result set full of duplicate data.
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.
I have 3 tables country_data, user_data and topic_data with table structures as given.
country_data:
name | code
---------------|---------------
India | IN
United States | US
Australia | AU
user_data:
user_ip | topic_code | country
---------------|---------------|---------------
192.168.1.1 | topic_code_1 | India
192.168.1.2 | topic_code_2 | United States
192.168.1.3 | topic_code_3 | Australia
topic_data:
name | code
---------------|---------------
topic_1 | topic_code_1
topic_2 | topic_code_2
topic_3 | topic_code_3
I have about one hundred thousand(100,000) rows in user_data table.
What I want is, I need to filter the count of users from each country with its corresponding country code for a given topic. For example, I need the count of users who viewed topic_2 in each country. The requered output format is
country_code | count
---------------|---------------
IN | 150
US | 120
AU | 100
Now please check my query:
SELECT cd.code, COUNT(ud.country) as count
FROM topic_data as td, user_data as ud, country_data as cd
WHERE td.name = 'topic_1' AND td.code = ud.topic_code AND ud.country = cd.name
GROUP BY ud.country
This one takes about 2 seconds to complete the execution in phpmyadmin. In the php webpage, it takes 15 seconds to load the page even in the server. by removing the group by in the query, ie GROUP BY ud.country, it takes more than 30 seconds to execute and the output is with the last country code and total of all countries visits. what am I doing wrong? please help.
----UPDATE----
Altered the tables using foreign keys and so as my queries too. now it works with lightning speed. thanks for those who helped.
The query doesn't look too bad IMO. However the normalization of the data looks a bit strange, e.g. why would you have a country (name) field on user_data table, just to join into country on name to look up the code? Instead, the more logical thing to me would be to reference country by country code (or other indexed key constraint). This would also save a join to country, if you just need the code as per your example query. If user_data is a high volume table, you will want to keep the data in it to a minimum to reduce IO when reading (density).
Also, as an aside, joining using JOIN instead of in the WHERE clause will improve the readability of your code, IMO:
SELECT cd.code, COUNT(ud.country) as count
FROM topic_data as td
INNER JOIN user_data as ud
ON td.code = ud.topic_code
INNER JOIN country_data as cd
ON ud.country = cd.name
WHERE td.name = 'topic_1'
GROUP BY ud.country;
To address the performance issues, check that the following indexes are in place:
Index on topic_data.name
Index on the foreign keys user_data.topic_code and user_data.country (or user_data.country_code if you do change the foreign key to user_data.country_code)
try this instead:
use below database structure for using numerical matching in INNER JOIN statement may decrease search time,
so index your id column of tables (e.g. primary key):
**country_data**
id|name | code
--|---------------|---------------
1 |India | IN
2 |United States | US
3 |Australia | AU
**user_data**
user_ip | topic_id | county_id
---------------|-----------|---------------
192.168.1.1 | 1 | 1
192.168.1.2 | 2 | 2
192.168.1.3 | 3 | 3
**topic_data**
id|name
--|------------
1 |topic_1
2 |topic_2
3 |topic_3
and run multiple INNER JOIN statment like:
SELECT cd.code, count(ud.topic_code) as count
FROM ud
INNER JOIN cd ON cd.id = ud.country
INNER JOIN td ON td.id = ud.topic_code
WHERE td.code='topic_1'
GROUP BY ud.country;
I have two tables (orders, order_lines) with a one to many relationship. The orders table will have one row and the order_lines table will have one row for each product attached to the order.
ORDERS
+----------+-------------+---------------+
|order_num | total_order | shipping_total|
+----------+-------------+---------------+
| 12345 | 75.00 | 15.00 |
+----------+-------------+---------------+
ORDER_LINES
+----------+-------------+-------+
| order_num| volume | price |
+----------+-------------+-------+
| 12345 |10 |25.00 |
+----------+-------------+-------+
| 12345 |20 |25.00 |
+----------+-------------+-------+
| 12345 |20 |25.00 |
+----------+-------------+-------+
I would like to sum the total_order & shipping_total columns in the ORDERS table and the volume & price columns in the ORDER_LINES table.
Query currently not working:
SELECT b_orders.bill_country, b_orders.ship_country
, SUM(volume) AS v, SUM(price) AS pt
, SUM(shipping_total) AS st, SUM(total_order) AS tot_o
FROM b_orders
JOIN b_order_lines
ON b_orders.order_num = b_order_lines.order_num
WHERE DATE(b_orders.order_date) BETWEEN '2012-04-02' AND '2012-04-06'
AND ship_country = 'USA'
AND b_order_lines.price > 0;
This query is returning the wrong values. I kind of know why but have no idea how to write the proper query...please help.
When you use an aggregate function line SUM, you need to tell the SQL server what columns are going to be used to GROUP BY for doing the sums.
So if you add the following to the bottom of your query:
GROUP BY
b_orders.bill_country, b_orders.ship_country
This will tell it to give you the sum for each unique combination of bill_country, ship_country in the data. Is this what you are looking for?
If bill_country and ship_country are going to be included in a query that also has aggregate functions like SUM, you need to group on them. I suspect all you need is to add this line at the end:
GROUP BY b_orders.bill_country, b_orders.ship_country;
If you don't need to see them, you can remove them from the SELECT statement and omit the grouping; you don't have to select columns to include them in the WHERE clause.
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.