Mysql Query with multiple query - php

First of all, I know the question title may have been asked before but my query is slightly different. I have searched but I couldn't find what I am looking for.IF anyone knows that this question asked before, please provide a link to that post.
So My question is this;
This is a minicab booking website. I have VEHICLES tables. In this table I have 4 vehicles. Saloon, Estate, MPV, Minibus. These vehicles have values like passengers and luggage capacity etc. as follows;
Saloon => passengers=4 AND luggage_capacity=5
Estate => passengers=4 AND luggage_capacity=8
MPV => passengers=6 AND luggage_capacity=10
Minibus=> passengers=10 AND luggage_capacity=30
Now, When visitor enters information of how many passengers and how many luggages, Sql query should return the correct vehicle for the information given.
Example: Visitor Selects 3 passengers and 5 luggages. This should return SALOON vehicle. If passengers is 6 and no luggage MPV should return as result and so on.
I have tried the following sql query but wrong vehicle is displayed.
SELECT name FROM vehicles WHERE passengers >= $passengers
AND luggage_capacity >= $luggage_capacity
I hope I could explain what I meant. Any help is appreciated.

you need to order and limit if you want only one vehicle:
SELECT name FROM vehicles WHERE passengers >= '$passengers' AND luggage_capacity >= '$luggage_capacity' ORDER BY passengers ASC, luggage_capacity ASC LIMIT 1

My guess is that the various capacity values in the database are being stored as strings rather than numbers. You could fix this in the query, using silent conversion:
SELECT name
FROM vehicles
WHERE passengers + 0 >= $passengers AND
luggage_capacity + 0 >= $luggage_capacity;
If this is the problem, it would be better to fix the table:
alter table vehicles modify column passengers int;
alter table vehicles modify column luggage_capacity int;

# Run from the console
set #p=3;
set #l=5;
select *
from `vehicles`
where `passengers` >= #p and `luggage_capacity` >= #l
order by `passengers`
limit 1;
+----+---------+------------+------------------+
| id | name | passengers | luggage_capacity |
+----+---------+------------+------------------+
| 1 | Saloon | 4 | 5 |
+----+---------+------------+------------------+

You do give default values to the $passangers and $luggage_capacity variables I hope and they are integers.
Also the result of this query might give you multiple results and in the wrong order. You should order the table the way you want and only select the smallest fitting car, something like this:
SELECT `name` FROM `vehicles` WHERE `passengers` >= $passengers AND `luggage_capacity` >= $luggage_capacity ORDER BY `passengers`, `luggage_capacity` LIMIT 1;
This will order the vehicles tables in ascending order first by passengers and secondly by luggage_capacity, select the first to fit and return only that, not all. If no result is found empty result set is returned. I tested the query and works like you asked.

Related

SQL finding specific character in table

I have a table like this
d_id | d_name | d_desc | sid
1 |flu | .... |4,13,19
Where sid is VARCHAR. What i want to do is when enter 4 or 13 or 19, it will display flu. However my query only works when user select all those value. Here is my query
SELECT * FROM diseases where sid LIKE '%sid1++%'
From above query, I work with PHP and use for loop to put the sid value inside LIKE value. So there I just put sid++ to keep it simple. My query only works when all of the value is present. If let say user select 4 and 19 which will be '%4,19%' then it display nothing. Thanks all.
If you must do what you ask for, you can try to use FIND_IN_SET().
SELECT d_id, d_name, d_description
FROM diseases
WHERE FIND_IN_SET(13,sid)<>0
But this query will not be sargable, so it will be outrageously slow if your table contains more than a few dozen rows. And the ICD10 list of disease codes contains almost 92,000 rows. You don't want your patient to die or get well before you finish looking up her disease. :-)
So, you should create a separate table. Let's call it diseases_sid.
It will contain two columns. For your example the contents will be
d_id sid
1 4
1 13
1 19
If you want to find a row from your diseases table by sid, do this.
SELECT d.d_id, d.d_name, d.d_description
FROM diseases d
JOIN diseases_sid ds ON d.d_id = ds.d_id
WHERE ds.sid = 13
That's what my colleagues are talking about in the comments when they mention normalization.

Group SQL rows by column value without flattening [duplicate]

Is it possible to sort in MySQL by "order by" using a predefined set of column values (ID) like order by (ID=1,5,4,3) so I would get records 1, 5, 4, 3 in that order out?
UPDATE: Why I need this...
I want my records to change sort randomly every 5 minutes. I have a cron task to update the table to put different, random sort order in it.
There is just one problem! PAGINATION.
I will have visitors who come to my page, and I will give them the first 20 results. They will wait 6 minutes, go to page 2 and have the wrong results as the sort order has already changed.
So I thought that if I put all the IDs into a session on page 2, we get the correct records even if the sorting had already changed.
Is there any other better way to do this?
You can use ORDER BY and FIELD function.
See http://lists.mysql.com/mysql/209784
SELECT * FROM table ORDER BY FIELD(ID,1,5,4,3)
It uses Field() function, Which "Returns the index (position) of str in the str1, str2, str3, ... list. Returns 0 if str is not found" according to the documentation. So actually you sort the result set by the return value of this function which is the index of the field value in the given set.
You should be able to use CASE for this:
ORDER BY CASE id
WHEN 1 THEN 1
WHEN 5 THEN 2
WHEN 4 THEN 3
WHEN 3 THEN 4
ELSE 5
END
On the official documentation for mysql about ORDER BY, someone has posted that you can use FIELD for this matter, like this:
SELECT * FROM table ORDER BY FIELD(id,1,5,4,3)
This is untested code that in theory should work.
SELECT * FROM table ORDER BY id='8' DESC, id='5' DESC, id='4' DESC, id='3' DESC
If I had 10 registries for example, this way the ID 1, 5, 4 and 3 will appears first, the others registries will appears next.
Normal exibition
1
2
3
4
5
6
7
8
9
10
With this way
8
5
4
3
1
2
6
7
9
10
There's another way to solve this. Add a separate table, something like this:
CREATE TABLE `new_order` (
`my_order` BIGINT(20) UNSIGNED NOT NULL,
`my_number` BIGINT(20) NOT NULL,
PRIMARY KEY (`my_order`),
UNIQUE KEY `my_number` (`my_number`)
) ENGINE=INNODB;
This table will now be used to define your own order mechanism.
Add your values in there:
my_order | my_number
---------+----------
1 | 1
2 | 5
3 | 4
4 | 3
...and then modify your SQL statement while joining this new table.
SELECT *
FROM your_table AS T1
INNER JOIN new_order AS T2 on T1.id = T2.my_number
WHERE ....whatever...
ORDER BY T2.my_order;
This solution is slightly more complex than other solutions, but using this you don't have to change your SELECT-statement whenever your order criteriums change - just change the data in the order table.
If you need to order a single id first in the result, use the id.
select id,name
from products
order by case when id=5 then -1 else id end
If you need to start with a sequence of multiple ids, specify a collection, similar to what you would use with an IN statement.
select id,name
from products
order by case when id in (30,20,10) then -1 else id end,id
If you want to order a single id last in the result, use the order by the case. (Eg: you want "other" option in last and all city list show in alphabetical order.)
select id,city
from city
order by case
when id = 2 then city else -1
end, city ASC
If i had 5 city for example, i want to show the city in alphabetical order with "other" option display last in the dropdown then we can use this query.
see example other are showing in my table at second id(id:2) so i am using "when id = 2" in above query.
record in DB table:
Bangalore - id:1
Other - id:2
Mumbai - id:3
Pune - id:4
Ambala - id:5
my output:
Ambala
Bangalore
Mumbai
Pune
Other
SELECT * FROM TABLE ORDER BY (columnname,1,2) ASC OR DESC

Select random row per distinct field value?

I have a MySQL query that results in something like this:
person | some_info
==================
bob | pphsmbf24
bob | rz72nixdy
bob | rbqqarywk
john | kif9adxxn
john | 77tp431p4
john | hx4t0e76j
john | 4yiomqv4i
alex | n25pz8z83
alex | orq9w7c24
alex | beuz1p133
etc...
(This is just a simplified example. In reality there are about 5000 rows in my results).
What I need to do is go through each person in the list (bob, john, alex, etc...) and pull out a row from their set of results. The row I pull out is sort of random but sort of also based on a loose set of conditions. It's not really important to specify the conditions here so I'll just say it's a random row for the example.
Anyways, using PHP, this solution is pretty simple. I make my query and get 5000 rows back and iterate through them pulling out my random row for each person. Easy.
However, I'm wondering if it's possible to get what I would from only a MySQL query so that I don't have to use PHP to iterate through the results and pull out my random rows.
I have a feeling it might involve a BUNCH of subselects, like one for each person, in which case that solution would be more time, resource and bandwidth intensive than my current solution.
Is there a clever query that can accomplish this all in one command?
Here is an SQLFiddle that you can play with.
To get a random value for a distinct name use
SELECT r.name,
(SELECT r1.some_info FROM test AS r1 WHERE r.name=r1.name ORDER BY rand() LIMIT 1) AS 'some_info'
FROM test AS r
GROUP BY r.name ;
Put this query as it stands in your sqlfiddle and it will work
Im using r and r1 as table alias names. This will also use a subquery to select a random some_info for the name
SQL Fiddle is here
My first response would be to use php to generate a random number:
$randId = rand($min, $max);
Then run a SQL query that only gets the record where your index equals $randID.
Here is the solution:
select person, acting from personel where id in (
select lim from
(select count(person) c, min(id) i, cast(rand()*(count(person)-1) +min(id)
as unsigned) lim from personel group by person order by i) t1
)
The table used in the example is below:
create table personel (
id int(11) not null auto_increment,
person char(16),
acting char(19),
primary key(id)
);
insert into personel (person,acting) values
('john','abd'),('john','aabd'),('john','adbd'),('john','abfd'),
('alex','ab2d'),('alex','abd3'),('alex','ab4d'),('alex','a6bd'),
('max','ab2d'),('max','abd3'),('max','ab4d'),('max','a6bd'),
('jimmy','ab2d'),('jimmy','abd3'),('jimmy','ab4d'),('jimmy','a6bd');
You can limit the number of queries, and order by "rand()" to get your desired result.
Perhaps if you tried something like this:
SELECT name, some_info
FROM test
WHERE name = 'tara'
ORDER BY rand()
LIMIT 1

php / mysql - how to get rankings of users?

for example i have a table like this :
name rating
matei 124
andrei 20
serj 25
john 190
mike 96
andy 245
tom 73
i need to output something like this(order by rating):
john's position is 2; or, tom's position is 5; (i don't need to get all result , just one )
How can I achieve this?
Thanks in advance
Generally order of rows in a query result is not guaranteed by MySQL unless ordering is explicitly specified with ORDER BY clause. If you have some separate ordering column, you may use query like the following:
SELECT count(1) as position
FROM table
WHERE order_column <= {john's order_column value};
If you don't have ordering column, I'd recommend you to define first, what does "john's position" and "tom's position" mean.
UPDATE:
AFAIU, you want to get position in list sorted by rating (sorry, I initially did not get it). So, rating would be your order_column. In this case, you should decide, how do you calculate position, if two guys have equal rating (who's position is higher?).
So, the query may look in the following way:
SELECT count(1) as position
FROM table
WHERE
rating > (SELECT rating FROM table WHERE id={user's ID});
SELECT COUNT(*) + 1
FROM users
WHERE (rating, name) <
(
SELECT rating, name
FROM users
WHERE name = 'john'
)
Note that if you will have duplicates on both name and rating, this query will assign the same rating to both of them.
Tables are more formally known as relations in database literature - they are not guaranteed to be ordered (they are sets of "tuples"), so your question doesn't make sense. If you need to rely on an order/position, you need to define an additional column (like an auto-incrementing ID column) to capture and store that info.
Is this any help > http://craftycodeblog.com/2010/09/13/rownum-simulation-with-mysql/ ?
Would offset not work like so?
SELECT * FROM Table ORDER BY rating DESC LIMIT 1,6
This would return 1 row that has been off setted by 6 rows ? or am I mistaken, the syntax would be
SELECT * FROM Table ORDER BY rating DESC LIMIT 1 , {{POS}}

Semi-Complicated PHP/MySQL Select Statement

I currently have 3 tables, which I'm using for people to make reservations for certain pieces of equipment.
Here are my tables:
tblEquipment:
id name description
1 Camera Takes pictures
2 Projector Projects pictures
3 Laptop Portable Computer
tblEvents:
id start end first_name last_name email
1 2009-08-10 2009-08-11 John Doe jd#email.com
2 2009-08-15 2009-08-16 Jane Doe jd#email.com
tblEventData:
id eventID equipmentID
1 1 1
2 1 2
Right now, a user will submit a query with their requested times, then they will see all available equipment.
So, using the exampe above, if a user is looking for equipment between 8/10-8/11, he will see that the only equipment that is available is: equipmentID 3 (Laptop).
How can I create my query to return only the available equipment based on the requested times?
This is what I've come up with so far, but can't get it to work:
SELECT tblequipment.id as name, tblEvents.start as start, tblEvents.end as end
FROM tblEquipment
INNER JOIN tblEventData on tblEventData.equipmentID = tblEquipment.id
INNER JOIN tblEvents on tbleventdata.eventID = tblEvents.id
WHERE NOT EXISTS(SELECT * FROM tblEvents WHERE $end >= start AND $start <= end)
Any ideas? Thanks!
The query you have now has a NOT EXISTS looking only for events that occur between the start and end times given. In other words, "select all equipment as long as there are no events in this timeframe." That's not what you want. You want: "select all equipment as long as there are no events using that equipment in this timeframe."
That translates to something like:
SELECT tblequipment.id as name
FROM tblEquipment
WHERE NOT EXISTS
(SELECT * FROM tblEvents
INNER JOIN tblEventData ON (tblEvents.id = tblEventData.eventID)
WHERE $end >= start AND $start <= end
AND tblEventData.equipmentID = tblEquipment.id)
EDIT: I've also removed the JOINs from the outer query, since they insist that you select only equipment that's reserved at some point, which is not at all relevant to the question you're trying to answer.
You do want to know what equipment is reserved, but inside the NOT EXISTS query, for the purposes of excluding it from your final results.
Try putting end in quotes so it is
`end`
I think mysql is interpreting end as a command rather than a field.
"end" is a reserved word in SQL. Try naming tblEvents.end something else.

Categories