How can I get data from 2 table based on specific condition - php

In MySQL database, I have 3 table called supplier, vehicle, and assigned table.
vehicle table:
vid vehicleName noOfSeat sid
========================================
13 x 10 28
14 x 8 28
15 x 12 28
16 x 14 29
17 x 4 29
18 x 8 30
assigned table
asgid bid sid vid did seatBooked assigned_start assigned_end
============================================================================
56 15 28 13 17 3 06/01/2018 02:01 06/01/2018 04:02
57 15 28 14 15 2 06/01/2018 02:01 06/01/2018 04:02
58 15 28 15 16 3 06/01/2018 02:01 06/01/2018 04:02
In a reservation page, I need to assign a vehicle to a selected date which is 06/01/2018 02:01 To 06/01/2018 04:02
Now I want to show all vehicle of a selected supplier as well as the number of seat from the vehicle table
But the condition is:
Those vehicles will be shown which has the number of seats available for my selected date: 6/01/2018 02:01 To 06/01/2018 04:02
For example:
It's must be shown following vehicle with the number of seats:
vid Mp pf Seat available
===========================
13 7 ( why 7? because on my selected date 3 seats booked)
14 6 ( why 6? because on my selected date 2 seats booked)
15 9 ( why 9? because on my selected date 3 seats booked)
16 14
17 4
18 8
Its something like bus ticket system.
My Current Query:
Currently, I am using the following query but it just removes those vid which is in my selected date but it's incorrect because as you can see that on my selected date few seats are available!!!
// my selected date: From = '$timestart' and To = '$timeend'
foreach ($sid as $key => $value) {
$vehicle->rowQuery("select * from vehicle where vid not in (
select vid from assigned where assigned_start BETWEEN '$timestart' AND '$timeend' AND assigned_end BETWEEN '$timestart' AND '$timeend' ) AND sid = $value ");
}
I can't imagine how can I solve it: =(
Your help is highly appreciated.

You can do something like this:
select vehicle.*, (noOfSeat -
(select sum(seatBooked)
from assigned
where sid = 28
and (assigned_start between '2018-01-06 02:01' and '2018-01-06 04:02' )
and (assigned_end between '2018-01-06 02:01' and '2018-01-06 04:02')
)) as seatsAvailable
from vehicle
having seatsAvailable > 0
http://sqlfiddle.com/#!9/c6bcb6/15

Related

styling table cells based on mysql group

We have a hotel booking table with data as following
id room night bookingid timestamp
1 1 2018-05-01 18 2018-04-07 01:34:41
2 1 2018-05-02 18 2018-04-07 01:34:41
3 1 2018-05-05 19 2018-04-07 01:34:40
4 1 2018-05-06 19 2018-04-07 01:34:40
5 2 2018-05-01 20 2018-04-07 01:34:39
6 2 2018-05-02 20 2018-04-07 01:34:39
7 2 2018-05-03 21 2018-04-07 01:34:37
8 2 2018-05-04 21 2018-04-07 01:34:37
current php code to block the dates in the table is:
$sql_query="select * from bookings where ('$year-$month-$i' = night) AND (room=$room)";
if there is result then td color become red as the bellow image
data is shown with php as a table cells with bookings as the following :
What i want to achieve is to group the bookings to show as the following
Any idea how to do so ?
would like to group the bookings to merge the cells then make the half cell red ( checkout and checkin day )

How can I rank a list of students and display their names in php

Mysql table structure looks like this:
subject ca quiz exam exam_cumulative positionineachcourse matric_no name
Maths 10 20 34 64 HT/001 John
Econs 14 14 40 68 HT/002 Mark
History 20 30 60 110 HT/003 Grace
Chem 15 15 50 80 HT/004 Alice
Bio 12 13 60 85 HT/005 Larry
How can get the position of each student in each course and then get also their overall positions like 1ST, SND, 3RD, 4TH and 5TH?

Laravel - Efficient Way to Query Monthly Data per Category

I'm working on a project that requires me to generate a report similar to this:
Category Total Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
-----------------------------------------------------------------------
Category 1 97 10 10 10 10 10 5 10 10 7 5 5 5
Category 2 120 10 10 10 10 10 10 20 10 5 5 10 10
Category 3 5 0 0 0 3 0 2 0 0 0 0 0 0
This report needs to be generated from data similar to this:
id category_id type year month amount
----------------------------------------------------------
1 1 16 2016 1 4
2 1 23 2016 1 6
3 1 76 2016 2 3
4 1 27 2016 2 3
5 1 18 2016 2 4
In the report, each month's number is simply the sum of the amount for that particular category, year, and month. I can do this just fine by querying the database for each month and for each category, but this type of approach doesn't scale very well if I need to generate a report with about a hundred categories because it would take over 1,200 queries (100 categories X 12 months)!
Any suggestions of how to make this more efficient?
Thanks!
The solution is grouping by two columns.I added the necessary code to format the results as you want.
Item::where('year', $year)
->groupBy('month', 'category_id')
->selectRaw('sum(amount) as sum, month, category_id')
->orderBy('category_id')
->orderBy('month')
->get()
->groupBy('category_id')
->map(function($item){
$item = $item->pluck('sum', 'month');
$item['total'] = $item->sum();
return $item;
});
Is this what you're looking for?
Category::where('year', 2016)
->select('month', 'year', DB::raw('SUM(amount) as amountTotal'))
->groupBy('month', 'year')
->get();

Decrement cells when records are deleted

So I have a simple MySQL table (block) as such:
SELECT * FROM `block` WHERE 1 ORDER BY `year`, `month`, `day`, `block`;
id year month day block te status
20000 2015 12 28 1 100000 1
20001 2015 12 28 2 100000 1
20002 2015 12 28 3 100001 1
20003 2015 12 28 4 100001 1
20004 2015 12 29 1 100001 1
20005 2015 12 29 2 100001 1
20006 2015 12 29 3 100002 1
20066 2015 12 30 1 100003 1
20078 2015 12 30 1 100007 1
20070 2015 12 30 1 100004 1
20067 2015 12 30 2 100003 1
20071 2015 12 30 2 100004 1
20079 2015 12 30 2 100007 1
20072 2015 12 30 3 100004 1
20080 2015 12 30 3 100007 1
20068 2015 12 30 3 100003 1
20069 2015 12 30 4 100003 1
20073 2015 12 30 4 100004 1
20074 2015 12 31 1 100004 1
20075 2015 12 31 1 100000 1
20076 2015 12 31 2 100000 1
20077 2015 12 31 3 100000 1
20007 2016 1 1 1 100017 1
20008 2016 1 1 2 100017 1
20009 2016 1 1 3 100017 1
My question is, how can I shift all the remaining rows up if I delete a contiguous section of rows?
For example, if I delete all blocks for 2015-12-28, I want all the remaining blocks to decrement to occupy the unused blocks on the schedule.
Let me know if this is confusing or unclear. Thanks.
I think a bit more background is required. What is your eventual goal?
Two options...
First Option
Check out the link below on numbering rows in MySQL. You can use something like this to make your blocks dynamic.
http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/
Second Option
If you are pulling data by day, just pull the data in order of the id and you can just assume that the blocks are in order in whatever application you use the data in.
For example, if I delete all blocks for 2015-12-28, I want all the remaining blocks to decrement to occupy the unused blocks on the schedule.
You do not actually specify what decrementing means. I think you want to shift the dates in all the blocks. But look here:
20000 2015 12 28 1 100000 1
20001 2015 12 28 2 100000 1
20002 2015 12 28 3 100001 1
20003 2015 12 28 4 100001 1
20004 2015 12 29 1 100001 1
20005 2015 12 29 2 100001 1
20006 2015 12 29 3 100002 1
20066 2015 12 30 1 100003 1
We have four blocks for 2015-12-28 and three for 2015-12-29. Say we delete the four 28's. What happens? Do three of the 29's shift to 28's, and the 30 become 29? Or do the three 29's and the 30 shift to fill the four places left by the 28's?
Depending on the strategy you need to choose different strategies. Perhaps you should define what exactly a block is, and what data is outside a "block", and supply a couple examples of a shift (with different numbers of days - e.g., 28 28 29 30 and you delete the two 28. BTW, can you delete only one? If so, what would happen then?).
Say each date can hold a fixed number of records
For example you can first count how many rows you're going to delete
SELECT COUNT(*) FROM ... WHERE day=28 AND month=12 AND year=2015
and then select the next items that have a later date. You then shift them, but you need to do this iteratively (once the 29's are gone, the 30's will shift, and so on). This may become quite expensive to calculate.
But in this case you might separate the date from the data:
TableA
2015 12 28
2015 12 28
2015 12 28
TableB
20000 100000 1
20001 100000 1
Now you need to join the tables in such a way that you can... well, join them. Whatever their cardinality. You might have a longer TableA than TableB, or vice versa.
This would be pretty easy in some RDBMS. In MySQL it's pretty awful (you can't even use CREATE VIEW to simplify the syntax because you'd need either a variable or a subquery in the view), and for small data sets you'd be better off by selecting TableA, then selecting TableB, and using a cycle in PHP:
// Run the query from tableA to get the dates
$TableADataSet = array();
while ($tuple = SQLFetch($rs)) {
$TableADataSet = $tuple;
}
// Run the query from tableB to get the rest
$TableBDataSet = array();
while ($tuple = SQLFetch($rs)) {
$TableBDataSet = $tuple;
}
// Now put them together.
for (;;) {
if (empty($TableADataSet)) {
if (empty($TableBDataSet)) {
break;
}
$TupleA = $EmptyRowFormattedAsTableA;
$TupleB = array_pop($TableBDataSet);
} else {
$TupleA = array_pop($TableADataSet);
if (empty($TableBDataSet)) {
$TupleB = $EmptyRowFormattedAsTableB;
} else {
$TupleB = array_pop($TableBDataSet);
}
}
// Now you have a row with dates and data "aligned".
// Missing data are taken by the sample rows EmptyRowFormattedAs... .
}
The result could be (simplifying)
2015 12 28 RowA
2015 12 28 RowB
2015 12 29 RowC
NULL NULL NULL RowD
and if you delete RowB, the rightmost part of the rows shifts upwards:
2015 12 28 RowA
2015 12 28 RowC
2015 12 29 RowD
In MySQL you first need to number the rows, and you have no RECNO() or ROW_NUMBER() function, so you do it like
SELECT #a:=#a+1 AS ranka,data1.* FROM ( SELECT * FROM TableA ORDER BY year, month, day ) AS data1, (SELECT #a:=0) AS init1;
and get your dates with a row number.
1 2015 12 28
2 2015 12 28
3 2015 12 29
You do the same for TableB. But now you have to do the "horizontal join" trick. We can be in one of these three cases:
B is longer A is longer Same length
A B A B A B
A B A B A B
- B A - A B
The "A B" part we can get with a JOIN. The "A -" part we get with a LEFT JOIN with a WHERE TableB.primarykey IS NULL. The "- B" part we get with a RIGHT JOIN WHERE TableA.primarykey IS NULL. Finally we put it all together with a UNION. And these three queries will need to be made with the awkward syntax above.
The (quite convoluted) query coming out of all this is
SELECT * FROM
( SELECT #a:=#a+1 AS rank1a, data1.*
FROM ( SELECT * FROM TableA ORDER BY year, month, day ) AS data1,
(SELECT #a:=0) AS init1
) AS ta
JOIN
( SELECT #b:=#b+1 AS rank1b, data2.*
FROM ( SELECT * FROM TableB ORDER BY something ) AS data2,
(SELECT #b:=0) AS init2 )
) AS tb
ON (rank1a = rank1b)
UNION
SELECT * FROM
( SELECT #c:=#c+1 AS rank2a, data3.*
FROM ( SELECT * FROM TableA ORDER BY year, month, day ) AS data3,
(SELECT #c:=0) AS init3
) AS tc
LEFT JOIN
( SELECT #d:=#d+1 AS rank2b, data4.*
FROM ( SELECT * FROM TableB ORDER BY something ) AS data4,
(SELECT #d:=0) AS init4 )
) AS td
ON (rank2a = rank2b) WHERE ( rank2b IS NULL )
UNION
SELECT * FROM
( SELECT #e:=#e+1 AS rank3a, data5.*
FROM ( SELECT * FROM TableA ORDER BY year, month, day ) AS data5,
(SELECT #e:=0) AS init5
) AS te
LEFT JOIN
( SELECT #f:=#f+1 AS rank3b, data6.*
FROM ( SELECT * FROM TableB ORDER BY something ) AS data6,
(SELECT #f:=0) AS init6 )
) AS tf
ON (rank3a = rank3b) WHERE ( rank3a IS NULL )
which, from a performance point of view, is probably a hog.

Mysql sum up the values of rows

SLNO UpazillaID CityArea VillageArea CharArea HillArea HaorArea TotalArea Year
6 1 11 44 11 11 11 11 2014
7 2 12 13 14 13 13 13 2013
I want to sum CityArea, VillageArea, CharArea, HillArea, HaorArea, TotalArea Where UpazillaID in 1,2.
Select (column1 + column2 + column3....) as totalcolumn. This will give you the sum per row.
SELECT (SUM(CityArea)+SUM(VillageArea)+SUM(CharArea)+SUM(CharArea)+SUM(CharArea)+SUM(TotalArea))
AS Total
FROM your_table
WHERE UpazillaID = 1

Categories