SQL: Select from Database up to a number (size) - php

I want to select rows up to a certain number (Size).
My SQL (SQL Fiddle):
id user_id storage
1 1 1983349
2 1 42552
3 1 367225
4 1 1357899
37 1 9314493
I want to select only all rows up to a certain number (size).
Like this here:
Select * from uploads where storage < 410000
it should get something like this here:
id user_id storage
2 1 42552
3 1 367225
The Summary of ID '2' and '3' is 409777.

You need some way of getting a cumulative sum. In MySQL, the easiest way uses variables:
select u.*
from (select u.*, (#s := #s + storage) as cume_storage
from uploads u cross join (select #s := 0) params
order by id
) u
where cume_storage < 410000;

Related

MySQL query skipping 001 numbers

This is a follow up to my previous question that was answered here - Determine the next number in database query with while loop in php
If I have a product tab
products TABLE
==============
ABC001
ABC002
ABC003
ABC005
==============
and use this
SELECT SUBSTR(t1.id, 4) + 1 as POSSIBLE_MIN_ID
FROM products t1
WHERE NOT EXISTS (
SELECT *
FROM products t2
WHERE SUBSTR(id, 1, 3)='ABC' AND SUBSTR(t2.id, 4) = SUBSTR(t1.id, 4) + 1
) LIMIT 1
I get the result of 4. However if I have the table looking
products TABLE
==============
ABC005
ABC006
ABC007
ABC008
==============
It gives me a result of 9. If I have none in the table it gives me a result of 2 not 1. And if I add the ABC001 in it works fine. Why is that and is there a way to fix it so it picks up the 1 as well? How can I have it work properly without having the ABC001 in there?
Thank!
If I understand correctly, you want the first unused 'ABCnnn'. So if 'ABC001' is still available get this, else try 'ABC002' and so on.
One method is to create all codes 'ABC001' to 'ABC999' and then remove the ones already in the table. From these take the least one.
You can use any method to generate your numbers or even have a table containing all allowed codes. Here I use binary math to create the numbers:
select min(code) as new_code
from
(
select concat('ABC', lpad(num,3,'0')) as code
from
(
select a.x + b.x * 2 + c.x * 4 + d.x * 8 + e.x * 16 + f.x * 32 +
g.x * 64 + h.x * 128 + i.x * 256 + j.x * 512 as num
from (select 0 as x union all select 1) a
cross join (select 0 as x union all select 1) b
cross join (select 0 as x union all select 1) c
cross join (select 0 as x union all select 1) d
cross join (select 0 as x union all select 1) e
cross join (select 0 as x union all select 1) f
cross join (select 0 as x union all select 1) g
cross join (select 0 as x union all select 1) h
cross join (select 0 as x union all select 1) i
cross join (select 0 as x union all select 1) j
) numbers
where num between 1 and 999
) codes
where code not in (select id from products);
Apart from this, I'd fix the bad database design. Store 'ABC' separately from the number. And if it's always 'ABC', don't store that string at all.
If it's just the biggest used ID plus 1 you are looking for:
select concat('ABC', lpad(coalesce(max(substr(id, 4, 3)), 0) + 1, 3, '0')) as new_id
from products;

Select unique pairs of users from a table at random

I want to create random user pairs between our database users.
I have the following user table:
Table: tbl_users
user_id | name
--------+--------------
1 | Jay
2 | Ram
3 | John
4 | Kevin
5 | Jenny
6 | Tony
I want to generate a random result like this:
from_id | to_id
--------+---------
1 | 6
5 | 3
2 | 4
Can this be done in MySQL only?
This is indeed a duplicate of a previous question, so the answer is there.
However, even if it is indeed possible in MySQL doing this there is not really recommended. PHP is a much better tool for handling this, as what you're doing is actually manipulating data as per some business rule. It'll be a lot easier to maintain by doing it in PHP, and I suspect that it'll be less resource-intensive as well.
A possible way to do this, which I'd prefer. Is to do a random sort in SQL, and then pair up two and two rows against each other. Something like this:
$grouping = {};
// Fetching both rows to ensure that we actually have an even number paired up.
while ($row = $res->fetch_array () && $row2 = $res->fetch_array ()) {
$grouping[] = {$row['name'], $row2['name']};
}
If you want to allow for an unmatched user to be listed, simply move the second fetch to the inside of the loop. Then deal with the potentially missing result there.
You can use the following code to generate your list:
select max(from_id) as from_id,
max(to_id) as to_id
from (
select
case when rownum mod 2 = 1 then user_id else null end as from_id,
case when rownum mod 2 = 0 then user_id else null end as to_id,
(rownum - 1) div 2 as pairnum
from (
select user_id, #rownum := #rownum + 1 as rownum
from
(select #rownum := 0) as init,
(select user_id from tbl_user order by rand()) as randlist
) as randlistrownum
) as randlistpairs
group by pairnum;
Step by step, this will:
order the userlist in random order
assign a rownumber to it (otherwise the order will have no meaning)
assign two consecutive rows the same pairnum (rownum = 1 and rownum = 2 get the value pairnum = 0, the next two rows will get pairnum = 1 and so on)
the first row of these paired rows will get the values from_id = user_id and to_id = null, the other row will be to_id = user_id and from_id = null
group by these pairs together to make them into one row
if you have an odd number of users, one user will end up with to_id = null, because it has no partner
A little more compact if you prefer shorter code:
select max(case when rownum mod 2 = 1 then user_id else null end) as from_id,
max(case when rownum mod 2 = 0 then user_id else null end) as to_id
from (
select user_id, #rownum := #rownum + 1 as rownum, (#rownum - 1) div 2 as pairnum
from
(select #rownum := 0) as init,
(select user_id from tbl_user order by rand()) as randlist
) as randlistpairs
group by pairnum;

MySQL, check if result has value, if not take another [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a table structure like this:
Page_id || type || user_id
1 1 0
2 2 0
3 3 0
4 1 1
5 2 1
6 3 1
From this table I would like to get page_id 4,5 and 6.
But I can also have table data like this
Page_id || type || user_id
1 1 0
2 2 0
3 3 0
4 1 1
5 2 1
Then I would like to get page_id 4, 5 and 3.
So I have to get all the types, but with the priority user_id and if there is no record with user_id 1, then take the one with 0
Have tried a lot. I know I can sort it with PHP, but I hope there is a way with MySQL.
Regards Andreas
//////// ANSWER /////////
I got a lot of suggestions, and I haven't tried them all, so I can't tell it they where right or not. But I have accepted an answer, which worked for me.Thank to everybody.
SELECT a.Type, a.Page_ID
FROM table a
INNER JOIN
(SELECT Type, MAX(User_ID) AS User_ID
FROM table
GROUP BY Type ) b
ON a.Type = b.Type AND a.User_ID = b.User_ID
You can execute a SELECT query as follow
SELECT Page_id
FROM table
WHERE user_id != 0
This SQL Fiddle demonstrates the below query:
SELECT DISTINCT
(
SELECT s1.Page_id
FROM myTable AS s1
WHERE m.type = s1.type
ORDER BY s1.Page_id
LIMIT 1
) AS PageID, type,
(
SELECT s2.user_id
FROM myTable AS s2
WHERE m.type = s2.type
ORDER BY s2.Page_id
LIMIT 1
) AS User
FROM myTable AS m
The results are the records where Page_id is 1, 2, and 4. As you can see in both of the sub queries I am ordering by Page_id to make sure the data is pulled from the same record and the first Page_id for that occurrence of the type is selected.
To return only one record unique to a couple columns, you'll want to use the GROUP BY statement. Then for any other column outside of the group by columns, you need to pick an aggregate function so it knows how to summarize the value if it finds multiple records in that group. In this case you want non-zero, so max() would work
SELECT type, max(user_id) as user_id
FROM table
GROUP BY type
how about that?
select page_id,type from (
select page_id,type, user_id from mytable
group by page_id,type, user_id having user_id=max(user_id)
) as x where user_id=1
Will there ever be multiple rows for a page where user_id is not zero? Because if not (if at most you only have one row per page where user_id = 1) then this will work:
SELECT ifNull(t1.page_id,t2.page_id) as page_id, t1.type,
CASE WHEN t2.page_id IS NULL THEN t1.user_id ELSE t2.user_id END as user_id
#start with all rows (including duplicates)
FROM myTable t1
#look for a user_id > 0 for this type
LEFT OUTER JOIN myTable t2 ON t1.type = t2.type AND t2.user_id > 0
WHERE t2.page_id IS NULL # if no record with user_id > 0 found, then no need to filter
# if a record with user_id > 0 was found, then filer out the user_id = 0 record
OR (t2.page_id IS NOT NULL AND t1.user_id > 0)
See in SQLFiddle: http://sqlfiddle.com/#!2/ba877/5

PHP SQL Has an issue

This is my table, I should fetch the MAX (id) of each status_id.
id status_id
10 1
11 1
12 2
13 2
14 2
15 4
16 4
So, I use this sql query, it works true and fetchs me all max ID.
select status_id, max(id) as max FROM `table`
where status_id in (1,2,3,4) group by status_id
This sql command fetchs me 3 MAX id using while.
11, 14, 16....
You see, there is not any suitable id to 3rd status_id. And if there is not any suitable id to 3rd status_id just mark it as zero. So I want that sql will bring these results:
11, 14, 0, 16
You can create a subquery which basically has all the ID's you need and have a left join against it.
SELECT a.status_ID,
IFNULL(MAX(b.id), 0) maxVal
FROM
(
SELECT 1 status_ID UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4
) a
LEFT JOIN `table` b ON a.status_id = b.status_id
GROUP BY a.status_id
SQLFiddle Demo
You can join with a temporary dummy table containing all ids and a stats_id value of 0:
SELECT dummy.status_id, COALESCE(MAX(id), 0) AS max
FROM (
SELECT 1 status_id
UNION SELECT 2 status_id
UNION SELECT 3 status_id
UNION SELECT 4 status_id
) dummy
LEFT JOIN `table`
ON dummy.status_id = table.status_id
GROUP BY dummy.status_id
But this does not scale and is a maintenance nightmare (you have to change the dummy-select in case a new status_id turns up). If you have a table containing ALL status_ids, replace the dummy-select with that table.

Get a rank, based on score, from an unordered MySql Database when given a Username

Okay so I have a table that has the following
KEY username password score
The above columns are not in any specific order.
I want to send my Database a username and have it send me back what rank that user name is based on its score. So for example if I had 10 people in there and the 3rd person in has the highest score. When I pass the 3rd persons username in I want it to send back 1.
Is this possible?
I have been trying things like this
$result = mysql_query("SELECT * FROM tablename where username='$username' ORDER BY score DESC");
but it doesnt seem to give me the row number
This will handle ranks that have the same score.
SELECT d.*, c.ranks
FROM
(
SELECT Score, #rank:=#rank+1 Ranks
FROM
(
SELECT DISTINCT Score
FROM tableName a
ORDER BY score DESC
) t, (SELECT #rank:= 0) r
) c
INNER JOIN tableName d
ON c.score = d.score
// WHERE d.username = 'Helen'
SQLFiddle Demo (Ranking with duplicates)
SQLFiddle Demo (with filtering)
for example
KEY username password score Ranks
1 Anna 123 5 3
2 Bobby 345 6 2
3 Helen 678 6 2
4 Jon 567 2 4
5 Arthur ddd 8 1
for better performance, add an INDEX on column Score,
ALTER TABLE tableName ADD INDEX (Score)
SELECT
(SELECT COUNT(*)+1 FROM tablename WHERE score > t.score) as rank,
*
FROM
tablename t
where
username='$username'
The ORDER BY in your query is useless since you're only returning one row.

Categories