I need a little bit of help with making a complicated query, i will try to explain what i am trying to accomplish down below.
Here is my data
table_one
+---------+---------+----------+----------+
| user_id | poly_id | in | out |
+---------+---------+----------+----------+
| 900 | 1 | 20-12-17 | 20-12-17 |
| 900 | 2 | 21-12-17 | 22-12-17 |
| 900 | 3 | 22-12-17 | 24-12-17 |
| 900 | 1 | 23-12-17 | 26-12-17 |
| 444 | 4 | 24-12-17 | 28-12-17 |
| 444 | 4 | 25-12-17 | 30-12-17 |
| 444 | 5 | 26-12-17 | 01-01-18 |
| 444 | 3 | 27-12-17 | 03-01-18 |
| 900 | 2 | 28-12-17 | 05-01-18 |
| 900 | 1 | 29-12-17 | 07-01-18 |
| 444 | 2 | 30-12-17 | 09-01-18 |
+---------+---------+----------+----------+
table_two
+----+---------+-------------+---------+
| id | name | type | product |
+----+---------+-------------+---------+
| 1 | city 1 | gas station | general |
| 2 | city 2 | workshop | general |
| 3 | city 3 | paint | bikes |
| 4 | city 4 | paint | general |
| 5 | city 5 | gas station | cars |
| 6 | city 6 | gas station | bikes |
| 7 | city 7 | paint | cars |
| 8 | city 8 | workshop | cars |
| 9 | city 9 | gas station | general |
| 10 | city 10 | gas station | cars |
| 11 | city 11 | gas station | general |
+----+---------+-------------+---------+
i have a working solution that looks like this
//results comes from somewhere else, it looks something like this for example:
array (
"user_id" => "poly_id of the last gas station"
"900" => 1,
"444" => 10
)
foreach ($result AS $res ) {
$query = "
SELECT
table_one.name AS name
FROM
`table_one`
LEFT JOIN
`table_two` ON table_one.poly_id = table_two.id
WHERE
`table_two`.type = 'gas station '
AND
table_one.user_id = $res['user_id']
AND
table_one.poly_id != $res['poly_id']
AND
table_one.in >= "some date from'
AND
table_one.out <= 'some date to'
AND
(FIND_IN_SET('general', table_two.product) > 0 OR FIND_IN_SET('cars', table_two.product) > 0 )
ORDER BY out DESC LIMIT 1
";
//if the results is not empty use the result['name']
}
The idea is: I have the user last gas station, but i need to find the previous one between a date range.
As i said, the above example is working just fine, however i need to be able to process multiple results at once, and sometimes the results are ~2000.
Which means 2000+ queries per request.
Is it even possible to somehow optimize this loop of queries into a single one, so I don't do 2000 queries per request ?
If possible, how :D
Thanks.
This query will return result contains user_id with it's last
enter in the given periode.
one thing here because you are
using date not date time if the user exit in the same
day two time you will have two record of that user you can skip the second
record in you code
select
user_id,
in,
out
from table_one t1
INNER JOIN (
select
user_id
max(out) as 'max_out',
from
table_one
where
in >= ? AND
out <= ? AND
ploy_id not in [list_of_unwanted_ploy_id]
-- you can specify any condition here
group by user_id
) l_out on t1.user_id = l_out.user_id and t1.out = l_out.max_out
where
t1.user_id in [list_of_user_id]
Related
i have a table for some coordination data.
like this:
+------+-------------+-------------+
| fdid | rtime | lat |
+------+-------------+-------------+
| 1 | 1589673600 | -40.1458523 |
| 2 | 1589673601 | -40.1458523 |
| 3 | 1589673602 | -40.1458523 |
| 4 | 1589673603 | -39.8598215 |
| 5 | 1589673604 | -39.8598215 |
| 6 | 1589673605 | -39.8598215 |
| 7 | 1589673606 | -39.8598215 |
| 8 | 1589673607 | -39.8598215 |
| 9 | 1589673608 | -39.8598215 |
| 10 | 1589673609 | -39.8598215 |
+------+-------------+-------------+
there are fields with name lat, representing Latitude
also the rtime is a timestamp.
these data are a vehicle on earth , now i have find when the vehicle go over / or pass the Equator
my query is like this
SELECT
*,
ROUND(rtime/1000,0) grtime,
count(*) acount,
min(rtime) mitime,
max(rtime) matime
FROM `fds_data`
WHERE `lat`<0.5 and lat>-0.5
GROUP BY grtime;
but i thing this is not a complete solution.is there any way for better result !?
In case consistent data (data record each second) you can find Equator pass by next simple query:
SELECT *
FROM `table` `t1`
JOIN `table` `t2` ON `t2`.`rtime` = (`t1`.`rtime` + 1) -- join next record
WHERE `t1`.`lat` * `t2`.`lat` <= 0; -- check Equator pass
I have a mySQL database table containing cellphones information like this:
ID Brand Model Price Type Size
==== ===== ===== ===== ====== ====
1 Apple A71 3128 A 40
2 Samsung B7C 3128 B 20
3 Apple ZX5 3128 A 30
4 Huawei Q32 2574 B 40
5 Apple A21 2574 A 25
6 Apple A71 3369 A 30
7 Samsung A71 7413 C 40
Now I want to create another table, that would contain counts for every possible combination of the parameters.
Params Count
============================================== =======
ALL 1000000
Brand(Apple) 20000
Brand(Apple,Samsung) 40000
Brand(Apple),Model(A71) 7100
Brand(Apple),Type(A) 6000
Brand(Apple),Model(A71,B7C),Type(A,B) 7
Model(A71) 12514
Model(A71,B7C) 26584
Model(A71),Type(A) 6521
Model(A71),Type(A,B) 8958
Model(A71),Type(A,B),Size(40) 85
And so on for every possible combination. I was thinking about creating a stored procedure (that i would execute periodically), that would perform queries with every existing condition like that, but I am a little stuck on how exactly should it look like. Or is there a better way how to do this?
Edit: the reason why I want to store information like this is to be able to show number of results in filter in client application, like in the picture.
I would like to create index on the Params column to be able to get the Count number for given hash instantly, improving performance.
I also tried querying and caching the values dynamically, but I want to try this approach as well, so I can compare which one is more effective.
This is how I am calculating the counts now:
SELECT COUNT(*) FROM products;
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple');
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple', 'Samsung');
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple') AND Model IN ('A71');
etc.
You can use a ROLLUP for this.
SELECT
model, type, size, COUNT(*)
FROM mytab
GROUP BY 1, 2, 3
WITH ROLLUP
With your sample data, we get the following:
| model | type | size | COUNT(*) |
| ----- | ---- | ---- | -------- |
| A21 | A | 25 | 1 |
| A21 | A | | 1 |
| A21 | | | 1 |
| A71 | A | 30 | 1 |
| A71 | A | 40 | 1 |
| A71 | A | | 2 |
| A71 | C | 40 | 1 |
| A71 | C | | 1 |
| A71 | | | 3 |
| B7C | B | 20 | 1 |
| B7C | B | | 1 |
| B7C | | | 1 |
| Q32 | B | 40 | 1 |
| Q32 | B | | 1 |
| Q32 | | | 1 |
| ZX5 | A | 30 | 1 |
| ZX5 | A | | 1 |
| ZX5 | | | 1 |
| | | | 7 |
The subtotals are present in the rows with null values in different columns, and the total is the last row where all group by columns are null.
I have a table that looks like the below and would like to a count of all bookings with a a count of all guests per week. There are 30 guest fields:
locations
| Field | Type |
| ------------ | ---------- |
| location | text |
| day_number | int(11) |
| month_number | int(11) |
| year | text |
| week_number | tinyint(4) |
| start | datetime |
| end | datetime |
| guest_1 | text |
| guest_2 | text |
| … | |
| guest_30 | text |
I am using:
select locaton, count(*) AS `Number of bookings per week`, week_number,
month_number, `month`
FROM locations
GROUP BY location, week_number;
That gets me:
| location | ...Bookings | week_number | month_number | January |
| ------------ | ----------- | ----------- | ------------ | -------- |
| Location One | 3 | 2 | 1 | January |
| Location One | 5 | 3 | 1 | January |
| Location One | 2 | 4 | 1 | January |
| Location One | 2 | 5 | 2 | February |
| Location One | 5 | 6 | 2 | February |
| Location One | 1 | 7 | 2 | February |
| Location One | 3 | 8 | 2 | February |
There are many locations.
How can I combine a count of guests over the 30 guest fields for each week and location in my query?
Thanks for any help in advance.
Simply count the guests for each combination and then sum up those counts
SELECT location,week_number,month_number,SUM(
(guest_1 <> "") +
(guest_2 <> "") +
(guest_3 <> "") +
....
(guest_30 <> "")
) AS num_guests
FROM locations
GROUP BY location,week_number,month_number
It's difficult because this table is not normalized.
In my opinion is this possible please re-create this solution and create new table GUEST with foreign key from LOCATION.
Next step is create subquery for example:
(you query) t1
having 30 = (select count(*) from GUEST where idlocation=t1.idlocation and year=t1.year, week_number=t1.week_number)
It will be more better resolve because in this situation you can add more guest without change logical table.
In your situation you always check every column separately.
I've the following table:
| id | Name | Date of Birth | Date of Death | Result |
| 1 | John | 3546565 | 3548987 | |
| 2 | Mary | 5233654 | 5265458 | |
| 3 | Lewis| 6546876 | 6548752 | |
| 4 | Mark | 6546546 | 6767767 | |
| 5 | Steve| 6546877 | 6548798 | |
And I need to do this for the whole table:
Result = 1, if( current_row(Date of Birth) - row_above_current_row(Date of Death))>X else 0
To make things easier, I guess, I created the same table above but with 2 extra id fields: id_minus_one and id_plus_one
Like this:
| id | id_minus_one | id_plus_one |Name | Date_of_Birth | Date_of_Death | Result |
| 1 | 0 | 2 |John | 3546565 | 3548987 | |
| 2 | 1 | 3 |Mary | 5233654 | 5265458 | |
| 3 | 2 | 4 |Lewis| 6546876 | 6548752 | |
| 4 | 3 | 5 |Mark | 6546546 | 6767767 | |
| 5 | 4 | 6 |Steve| 6546877 | 6548798 | |
So my approach would be something like (in pseudo code):
for id=1, ignore result. (Because there is no row above)
for id=2, Result = 1 if( (Where id=2).Date_of_Birth - (where id_minus_one=id-1).Date_of_Death )>X else 0
for id=3, Result = 1 if( (Where id=3).Date_of_Birth - (where id_minus_one=id-1).Date_of_Death)>X else 0
and so on for the whole table...
Just ignore id_plus_one if there is no need for it, I'll use it later for the same thing. So, if I manage to do this for id_minus_one I'll manage for id_plus_one as they are the same algorithm.
My question is how to pass that pseudo code into SQL code, I can't find a way to relate both ids in just one select.
Thank you!
As you describe this, it is just a self join with some logic on the select:
select t.*,
((t.date_of_birth - tprev.date_of_death) > x) as flag
from t left outer join
t tprev
on t.id_minus_one = tprev.id
My issue is mostly that im not sure how to word what I need in a search.
mysql> SELECT * FROM `accounts`;
+----+--------+---------+----------+
| id | status | oplevel | username |
+----+--------+---------+----------+
| 10 | 1 | 0 | root |
| 11 | 1 | 1 | Xylex |
| 12 | 1 | 16 | Anubis |
| 13 | 0 | 16 | Kami |
| 14 | 1 | 16 | Zorn |
+----+--------+---------+----------+
mysql> SELECT * FROM `networks`;
+-----------+-----------+-------------+-----------------+
| networkid | accountid | networkname | serveraddress |
+-----------+-----------+-------------+-----------------+
| 1 | 10 | Fakenet | irc.fakenet.org |
| 2 | 10 | Undernet | irc.under.net |
| 3 | 12 | Takenet | irc.takenet.com |
| 4 | 13 | Examplenet | irc.example.org |
+-----------+-----------+-------------+-----------------+
I have this accounts table and this networks table
I need a single query that will return the address of the IRC network, ONLY IF the corresponding account id status column is 1 (enabled)
Ive been searching for hours.
What Do?
looks like a simple join to me:
select serveraddress from accounts join networks on id=accountid and id=YOUR_ACCOUNT_ID_HERE
Or
select serveraddress from networks where accountid=YOUR_ID and exists(select * from accounts where id=accountid and status)
Many ways to go about this..
select serveraddress from networks, accounts where networks.accountid = accounts.id and accounts.satus=1;
Is it what you're looking for?
I've updated the query to place account id.
select acc.id, acc.username, nw.serveraddress from accounts acc join networks nw on acc.id = nw.accountid where acc.status == 1 and acc.id=XXX