Semi-Complicated PHP/MySQL Select Statement - php

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.

Related

Mysql Query with multiple query

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.

Running a query on query result? (PHP + SQL)

I currently have a table with 1,100,000 rows which contains user's data.
Its format is sort of like this:
User_Id Date Action
I was wondering, instead of searching each time on the whole table for the actions that were made by a specific user on a specific date by doing the following:
SELECT Action FROM USERS_TABLE WHERE Date=08092014 AND User_Id=5
SELECT Action FROM USERS_TABLE WHERE Date=09092014 AND User_Id=5
SELECT Date FROM USERS_TABLE WHERE Action="Shopping" AND User_Id=5
SELECT Date FROM USERS_TABLE WHERE Action="Eating" AND User_Id=5
etc.
Maybe I could do something like that:
SELECT * FROM USERS_TABLE WHERE User_Id=5
And on top of this query's results I could run the above queries, which I think will result a faster execution time (correct me if I'm wrong)
Do you guys know how to do that?
You could combine all of those queries into one query using an or.
SELECT *
FROM USERS_TABLE
WHERE (Date = 09092014 OR Date = 08092014)
AND (Action="Shopping" OR Action="Eating")
AND User_Id = 5
I assume you have a table with unique users ids. if you don't, you might consider it? How can a profile be managed if there is no single entry for a single user? anyway that's not my business, but let's just assume you have such a table, with a unique field with the User_Id
it's named USERS here
SELECT Action,Date
FROM USERS
LEFT JOIN USERS_TABLE AS Actions
ON (Actions.User_Id=USERS.User_Id AND Date IN (08092014,09092014))
LEFT JOIN USERS_TABLE AS Dates
ON (Dates.User_Id=USERS.User_Id AND Action IN ("Shopping","Eating"))
WHERE USERS.User_Id=5
be sure to index User_Id, Date And Action since we are searching on them.
I would do a crosstab query, after I indexed the User_Id column -
SELECT `Date`,
SUM(IF(`Action` = 'Eating', 1, 0)) AS `Eating`,
SUM(IF(`Action` = 'Shopping', 1, 0)) AS `Shopping`
FROM `USERS_TABLE`
WHERE `User_Id` = 5
GROUP BY `Date`
You'll get a result like this -
+-------------+---------------+----------+
Date Eating Shopping
+-------------+---------------+----------+
2002-03-01 59 72
2002-03-02 28 0
2002-03-03 22 17
2002-03-04 36 13
2002-03-06 12 0
+-------------+---------------+----------+
For expediency I might store this data in a temp table (with a user id column). This can be modified to accept date ranges and other limitations. That gives me some additional flexibility down the line when I need to aggregate date from multiple users.
I think what you mean is answered by this:
select action, actiondate
from
(select *
from USERS_TABLE
where user_id = 5) as filter
Fiddle here.
The derived table basically acts as the filter you describe.
Whether it would be any faster is hard to predict - I'd run it on your production system, and see what the query plan says.

php mysql display name once instead of the number of times it has been entered

I have this query but it returns the name of author the number of times it exists in the database ..
$query = "SELECT bauthor FROM info WHERE Cat1 = 'novel'";
$result = MySQL_query($query);
i want the author's name to be displayed once and the number of books he has to be in a bracket ...for example author's name is aaaaa and he has written 20 books so wen i run this query it shows mw his name 20 times but i want it to be in this way aaaa(20)
I can't do much without your full schema, but try using the COUNT feature with a GROUP BY clause, like
SELECT bauthor, COUNT(books) AS numbooks FROM info WHERE ... GROUP BY bauthor
EDIT: See this SQLFiddle for an example: http://sqlfiddle.com/#!2/bb5f5/1/0

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}}

Categories