Select rows before and after matching row in specified order - php

I have a table of users with points column in it. User id is not autoincrement, but it is user ID from Twitter.
I'm trying to select user by username (so always 1 user) and select 10 rows before it and 10 rows after it.
Also, it should be ordered by points and I should get ranking of selected user.
I'm using Laravel 4 and Eloquent, but I'm pretty sure it can't be done with Eloquent.
+-----------+--------------+------------+
| id | username | vote_count |
+-----------+--------------+------------+
| 123456789 | user1 | 150 |
| 123456789 | user2 | 101 |
| 123456789 | user3 | 90 |
| 123456789 | user4 | 88 |
| 123456789 | user5 | 70 |
| 123456789 | user6 | 67 |
| 123456789 | user7 | 65 |
| 123456789 | user8 | 55 |
| 123456789 | user9 | 54 |
| 123456789 | user10 | 45 |
| 123456789 | user11 | 44 |
| 123456789 | user12 | 42 |
+-----------+--------------+------------+
Let's say I want to order this table by vote_count, than select user5 and select 2 users that are before and after it in given order.
Hope I'm being clear with this one

Something like this :
SQLFiddle demo
select * from
(
select * from
(
select * from t where vote_count<=
(select vote_count
from t
where username ='user5')
ORDER BY vote_count desc
LIMIT 3
) as T1
UNION
select * from
(
select * from t where vote_count>
(select vote_count
from t
where username ='user5')
ORDER BY vote_count ASC
LIMIT 2
) as T2
) as T3 ORDER BY VOTE_COUNT DESC

You could use union
(SELECT id, vote_count
FROM `table`
WHERE id > 123456789
LIMIT 10)
UNION
(SELECT id, vote_count
FROM `table`
WHERE id <= 123456789
LIMIT 10)
ORDER BY vote_count

You can check the SQL FIDDLE
select * from ( (select A.vote_count,A.username from t A join t B on A.vote_count<B.vote_count where B.username='user5' order by A.vote_count DESC limit 2)
UNION
(select A.vote_count,A.username from t A join t B on A.vote_count>=B.vote_count where B.username='user5' order by A.vote_count limit 3)) as T order by vote_count desc

Related

Stuck in building MySQL query

Given an example of table:
id | item_id | user_id | bid_price
----------------------------------
The task is to select rows with minimum bid_price for each item_id in the provided set.
For example: item_id = [1, 2, 3] - so I need to select up to three (3) rows, having a minimum bid_price.
Example of data:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
2 | 1 | 12 | 2
3 | 1 | 13 | 3
4 | 1 | 14 | 1
5 | 1 | 15 | 4
6 | 2 | 16 | 2
7 | 2 | 17 | 1
8 | 3 | 18 | 2
9 | 3 | 19 | 3
10 | 3 | 18 | 2
Expected result:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
7 | 2 | 17 | 1
8 | 3 | 18 | 2
Actually, I'm using Symfony/Docine DQL, but it will be enough with a plain SQL example.
For the all the columns in the rows you could use a inner join on subselect for min bid price
select m.id, m.item_id, m.user_id, m.bid_price
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
or .. if you have some float data type you could use a acst for unsigned
select m.id, m.item_id, m.user_id, cast(m.bid_price as UNSIGNED)
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
You can use MIN() with GROUP BY in the query:
SELECT id, item_id, MIN(bid_price) AS min_bid, user_id
FROM your_tbl
GROUP BY item_id
HAVING item_id in(1, 2, 3);
Use this query:
SELECT id, item_id, user_id, min(bid_price) as bid_price
FROM YOUR_TABLE_NAME
GROUP BY item_id;

MySQL: Select rank from grouped result

I have a table which contains data from a radio station, and which songs it played. All the songs played are stored in a table named 'radio_data'. This table looks like this:
-----------------------------------------------
| id | artist_id | song_id | play_date |
| 1 230 420 2017-5-12 12:00 |
| 2 212 971 2017-5-12 12:01 |
| 3 230 420 2017-5-12 13:00 |
| 4 230 420 2017-5-12 15:00 |
| 5 212 971 2017-5-12 15:02 |
-----------------------------------------------
I have a page where some statistics for one specific song is displayed. On this page i would like to show the rank of the song, based on how much it has been played.
Let's say that if i am om the page for song_id 420, it would rank as place 1 out of 2 songs.
I have no idea where to start. I have this query to group the songs:
SELECT COUNT(`id`) AS `playcount`, `artist_id`, `song_id` FROM `radio_data` GROUP BY `song_id` ORDER BY `playcount` DESC
This gives me the following result:
-----------------------------------
| playcount | artist_id | song_id |
| 3 230 420 |
| 2 212 971 |
-----------------------------------
Thanks in advance for your help!
You can use user variables for displaying the rank:
set #rn := 0;
select #rn := #rn + 1 as rank,
song_id,
artist_id,
count(*) as times_played
from your_table
group by song_id, artist_id
order by times_played desc;
If you want to get top, say 10, songs you can add a limit 10 at the end.
SELECT
song_id, count(id) played_times, #rank := #rank +1 rank
FROM
(
songs_plays CROSS JOIN (SELECT #rank := 0)rank
)
GROUP BY song_id
ORDER BY played_times DESC
the result is
+------------+--------------+--------+
| song_id | played_times | rank |
+------------+--------------+--------+
| 420 | 3 | 1 |
| 971 | 2 | 2 |
+------------+--------------+--------+
run it live on SQL fiddle (http://sqlfiddle.com/#!9/1c48d8/5)

How to fetch data from table as per column value using PHP and MySQL

I need to filter value from table as per column value using PHP and MySQL. Here is my data:
db_images:
image_id member_id subcat_id from_day to_day
1 220 56 1 3
2 220 56 1 3
3 220 56 1 1
4 120 22 1 5
5 120 22 2 4
Here is my query:
$qry=mysqli_query($connect,"select * from db_iamges group by member_id,subcat_id order by image_id desc");
Using my query I am getting a record like below:
image_id member_id subcat_id from_day to_day
3 220 56 1 1
I need the to_day should always be higher value. If same member_id and subcat_id is present the the to_day will be always higher value and the from_day will be always smaller value. The expected output should like below.
image_id member_id subcat_id from_day to_day
1 220 56 1 3
4 120 22 1 5
It seems you have syntax problems, because if you copy-paste, you put "db_iamges". I made a table:
mysql> select * from prueba1;
+----------+-----------+-----------+----------+--------+
| image_id | member_id | subcat_id | from_day | to_day |
+----------+-----------+-----------+----------+--------+
| 1 | 220 | 56 | 1 | 3 |
| 2 | 220 | 56 | 1 | 3 |
| 3 | 220 | 56 | 1 | 1 |
| 4 | 120 | 22 | 1 | 5 |
| 5 | 120 | 22 | 2 | 4 |
| 6 | 120 | 22 | 2 | 9 |
| 7 | 120 | 22 | 2 | 2 |
+----------+-----------+-----------+----------+--------+
7 rows in set (0.00 sec)
And:
mysql> select image_id, member_id, subcat_id, min(from_day), max(to_day) from prueba1 group by member_id, subcat_id order by image_id asc;
+----------+-----------+-----------+----------+-------------+
| image_id | member_id | subcat_id | from_day | max(to_day) |
+----------+-----------+-----------+----------+-------------+
| 1 | 220 | 56 | 1 | 3 |
| 4 | 120 | 22 | 1 | 9 |
+----------+-----------+-----------+----------+-------------+
2 rows in set (0.00 sec)
It is working
EDIT: Updated, as I didn't understand your main problem.
Select
T.*
From db_images t
Inner join (
Select member_id, subcat_id, max(to_day) to_day
db_images group by member_id,subcat_id
) t2 on t.member_id = t2.member_id
And t.Subcat_id = t2.subcat_id
And t.to_day = t2.to_day;
use max(column name) to get higher value .
select image_id, member_id,subcat_id,from_day, max(to_day) as to_day from from db_iamges group by member_id,subcat_id order by image_id desc
try this
select t1.* from db_images t1 inner join(select max(member_id) as
mid,max(subcat_id) as cid,min(from_day) as fdy from db_images group
by member_id) t2 on t1.member_id = t2.mid and t2.cid = t1.subcat_id
and t2.fdy = t1.from_day group by member_id order by image_id asc;
check here

MySQL - Group by multiple columns from same table

I have a table similar to the following
sno | booking_id | room_type | gender | age | amount | days
1 | 2016JUL001 | AC | Male | 25 | 1000 | 15
2 | 2016JUL001 | AC | Male | 42 | 1000 | 15
3 | 2016JUL001 | AC | Male | 28 | 1000 | 15
4 | 2016JUL010 | N AC | Female | 45 | 1000 | 15
5 | 2016JUL010 | N AC | Female | 46 | 1000 | 15
6 | 2016JUL005 | N AC | Male | 28 | 1000 | 15
7 | 2016JUL005 | N AC | Female | 35 | 1000 | 15
8 | 2016JUL009 | AC | Female | 26 | 1000 | 15
9 | 2016JUL009 | AC | Female | 25 | 1000 | 15
... so on
Expected output [If I want to get gender='Female']
sno | booking_id | room_type | gender | age | amount | days
4 | 2016JUL010 | N AC | Female | 45 | 1000 | 15
5 | 2016JUL010 | N AC | Female | 46 | 1000 | 15
8 | 2016JUL009 | AC | Female | 26 | 1000 | 15
9 | 2016JUL009 | AC | Female | 25 | 1000 | 15
Expected output [If I want to get gender='Male']
sno | booking_id | room_type | gender | age | amount | days
1 | 2016JUL001 | AC | Male | 25 | 1000 | 15
2 | 2016JUL001 | AC | Male | 42 | 1000 | 15
3 | 2016JUL001 | AC | Male | 28 | 1000 | 15
Expected output [If I want to get gender='Male' AND gender='Female']
sno | booking_id | room_type | gender | age | amount | days
6 | 2016JUL005 | N AC | Male | 28 | 1000 | 15
7 | 2016JUL005 | N AC | Female | 35 | 1000 | 15
NOTE: I want 3 separate individual QUERIES to get the above outputs
Thanks in advance
First query :
SELECT sno, booking_id, room_type, gender, age
FROM customer_data
WHERE booking_id IN ( SELECT booking_id FROM customer_data
WHERE gender='female' AND age>0 and RIGHT(booking_id,1) <> '1'
GROUP BY booking_id HAVING COUNT(*) > 1 )
ORDER BY booking_id ASC, age ASC
Second :
SELECT sno, booking_id, room_type, gender, age
FROM customer_data
WHERE booking_id IN ( SELECT booking_id FROM customer_data
WHERE gender='male' AND age>0
GROUP BY booking_id HAVING COUNT(*) > 1 )
ORDER BY booking_id ASC, age ASC
And third:
SELECT sno, booking_id, room_type, gender, age
FROM customer_data
WHERE booking_id IN ( SELECT booking_id FROM customer_data
WHERE gender IN('male','female') AND age>0
GROUP BY booking_id HAVING COUNT(distinct gender) = 2 )
ORDER BY booking_id ASC, age ASC
If in the first two you wanted only booking_id that has only 1 gender, add to the having clause :
AND COUNT(distinct gender) = 1
After lot of tries, I am able to get the data I want
Query ['Female']
SELECT sno, bd.booking_id, bd.room_type, bd.gender, bd.age
FROM customer_data bd
INNER JOIN (
SELECT booking_id, GROUP_CONCAT(DISTINCT gender) AS g
FROM customer_data
WHERE gender!='' AND age>0
GROUP BY booking_id
HAVING COUNT(booking_id) > 1
ORDER BY booking_id ASC, gender DESC
) cbd
WHERE cbd.booking_id = bd.booking_id AND cbd.g = 'Female'
Query ['Male']
SELECT sno, bd.booking_id, bd.room_type, bd.gender, bd.age
FROM customer_data bd
INNER JOIN (
SELECT booking_id, GROUP_CONCAT(DISTINCT gender) AS g
FROM customer_data
WHERE gender!='' AND age>0
GROUP BY booking_id
HAVING COUNT(booking_id) > 1
ORDER BY booking_id ASC, gender DESC
) cbd
WHERE cbd.booking_id = bd.booking_id AND cbd.g ='Male'
Query ['Male and Female']
SELECT sno, bd.booking_id, bd.room_type, bd.gender, bd.age
FROM customer_data bd
INNER JOIN (
SELECT booking_id, GROUP_CONCAT(DISTINCT gender ORDER BY gender DESC) AS g
FROM customer_data
WHERE gender!='' AND age>0
GROUP BY booking_id
HAVING COUNT(booking_id) > 1
ORDER BY booking_id ASC, gender DESC
) cbd
WHERE cbd.booking_id = bd.booking_id AND cbd.g = 'Male,Female'
Your schema appears somewhat flawed. Nevertheless, here's something to think about...
SELECT booking_id
, COUNT(DISTINCT gender) x
FROM customer_data
WHERE gender IN ('Male','Female') <-- not strictly necessary if there are only two genders.
GROUP
BY booking_id;

Get customers that has more than 2 orders but logged in less than 3 times though SQL

I'm trying to get all customers who has more than 2 orders, but only logged in less than 3 times.
I'm logging when users are logging in.
But for some reason my returns only one row with wrong data...
"user_log" table (user_id 19 has logged in only once)
| user_log_id | date | user_id | type | module_id | unit_id |
|-------------|------|---------|------|-----------|---------|
| 1 |"date"| 19 | 1 | NULL | NULL |
| 2 |"date"| 20 | 1 | NULL | NULL |
| 3 |"date"| 20 | 1 | NULL | NULL |
| 4 |"date"| 20 | 1 | NULL | NULL |
| 5 |"date"| 20 | 1 | NULL | NULL |
|-------------|------|---------|------|-----------|---------|
"orders" table where user_id 19 has 2 orders (Removed unnecessary columns)
| order_id | user_id | status |
|----------|---------|--------|
| 10 | 19 | 1 |
| 11 | 19 | 1 |
| 12 | 20 | 1 |
| 13 | 21 | 1 |
| 14 | 31 | 1 |
|----------|---------|--------|
What i want (User_id has 2 orders, but has logged in less than 3 times)
| user_id |
|---------|
| 19 |
|---------|
This is how my SQL looks like right now.
$sql = "SELECT
ul.*, orders.order_id, orders.user_id, orders.firstname, orders.lastname, COUNT(ul.user_id) AS occourcence
FROM
orders
LEFT JOIN
user_log AS ul
ON
orders.user_id = ul.user_id
WHERE
orders.status = 1
AND
ul.type = 1
GROUP BY
orders.user_id
HAVING
COUNT(orders.user_id) > 1
ORDER BY
orders.order_id DESC";
select user_id,count(user_log_id) from user_log
where user_id in
(
select user_id from Orderes
group by user_id
having count(order_id) =2
)
group by user_id
having count(user_log_id) < 3
Avoiding any sub queries (and assuming you meant logged in 3 times, and making 2 or more orders - to match your example data):-
SELECT a.user_id
FROM user_log a
INNER JOIN orders b
ON a.user_id = b.user_id
GROUP BY a.user_id
HAVING COUNT(DISTINCT user_log_id) < 3 AND COUNT(DISTINCT order_id) >= 2;
SQL fiddle here:-
http://www.sqlfiddle.com/#!2/1b719/3
Try this
select o.user_id from
(
select user_id from orders
where status=1
group by user_id having count(*)>=2
) as o left join
(
select user_id from user_logs
where type=1
group by user_id having count(*)<3
) as l
on o.user_id=l.user_id

Categories