MySQL Order Sorting based on particular order - mysql

I have a table
galleries(id, name, file, ...)
the view is a slideshow of the photos. But its order depends on the id of the photo clicked from the album view.
Lets say the User clicks 4 out of the 10 records
then i want to sort the order as
4, 1, 2, 3, 5, 6, ...
or any order but keeping 4 at the start.

For MySQL specially you can do
select * from galleries
order by id <> $clickedNumber,
id
or generally in ANSI SQL
select * from galleries
order by case when id = $clickedNumber then 1 else 2 end,
id

Related

How to find out next available number

In my MySQL table I have field called sequence where I have values like
1 , 2, 3, 5, 6, 7, 8, 10 some of the sequence number are skiped due to deleted records. How do I find out next available number from given number. let's say if I need next number from 3 , how do I get number 5 as my next number in sequence not the 4.
To find out the next ID after 3 that appears in your table, you should do
SELECT id FROM thetable WHERE id>3 ORDER BY id ASC LIMIT 1
This just considers IDs that are greater than 3, in ascending order, and then takes the first one on that list. If it returns you one result, then that's the next one used in the table; if it doesn't return a result at all, then the ID you gave it was already the highest one in the table (or, strictly speaking, at least as high as the highest one in the table).
If you want a general expression that works to get the next available number, then you can use an aggregation query:
select coalesce(max(id), maxid + 1) as NextAvailableId
from table t cross join
(select max(id) as maxid from table t) x
where id > 3;
Or, if you don't like the cross join, you can use conditional aggregation:
select coalesce(max(case when id > 3 then id end), max(id)) as NextAvailableId
from table t;

How can I catch neighbors of a specific row with order by in mysql?

I will give you a simple example of what I want
let say that I have an articles table with the following ids (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
now the visitor want to sort this articles by article title then with the author name so the query will look like this
SELECT `articles`.`id`, `articles`.`title`, `articles`.`body`, `authors`.`id`, `authors`.`name` from `articles`
left join `authors` on `articles`.`author_id` = `authors`.`name`
ORDER BY `articles`.`title` ASC, `authors`.`name` ASC;
which may result the following order (5, 9, 8, 6, 4, 1, 3, 10, 2, 7)
then the visitor visits the detail page of article number 4, now from this page I want to navigate throw his results which is (5, 9, 8, 6, 4, 1, 3, 10, 2, 7)
so I want to catch the article number "6" as previous article and article number "1" as next article
how can I perform this operation using Mysql while in article details page I have just the article ID and the search criteria and search order.
Note: the solution should consider the performance because I have a table which may reach 1,000,000 row
In SQL, you would want to use something like ROW_NUMBER() OVER. It seems this isn't available in MySql; see this question.
This is rather simple.
The previous article will be the one with the highest (so to speak) title, that is still less than the title of article 4. You can find that like this:
SELECT MAX(title) AS maxTitle
FROM articles
WHERE title < (SELECT title FROM articles WHERE id = 4);
If you want to get the id of that article, you can join it back to the original table:
SELECT a.id
FROM articles a
JOIN(
SELECT MAX(title) AS maxTitle
FROM articles
WHERE title < (SELECT title FROM articles WHERE id = 4)) tmp ON tmp.maxTitle = a.title;
To get the next article, you just flip all of your conditions:
SELECT a.id AS nextArticle
FROM articles a
JOIN(
SELECT MIN(title) AS maxTitle
FROM articles
WHERE title > (SELECT title FROM articles WHERE id = 4)) tmp ON tmp.maxTitle = a.title;
Here is an SQL Fiddle example that has rows ordered in the same way you do, and does return values 6 and 1 as you expect.

searching for records in mysql using or - and - not in query

I think I am getting turned around when looking at this. I am trying to get all patron records relating to transactions that have a transaction item with one of a number of ids (1 or 2) as well as transaction items with other ids (3 or 4) but not with transaction items with other ids (5 or 6)
The structure is:
=patron=
id
fname
lname
email
phone
=trans=
id
id_org
id_patron
=trans_item=
id
id_trans
id_perf
I was trying the following:
SELECT
patron.email,
patron.fname,
patron.lname,
patron.phone
FROM
trans_item,
trans,
patron
WHERE
trans_item.id_perf IN (1,2)
AND
trans_item.id_perf IN (3,4)
AND
trans_item.id_perf NOT IN (5,6)
AND
trans_item.id_trans = trans.id
AND
trans.id_org = 1
AND
trans.id_patron = patron.id
GROUP BY
patron.id
ORDER BY
patron.email DESC,
patron.phone DESC
I'm aware that saying the id needs to be 2 AND 4 is always going to return nothing but I need to have it as if id is in (1,2) AND (3,4) so it can be 1 or 2 but also needs to be in 3 or 4
For Clarity:
I am trying to get patrons who have gone to performance 1 OR 2 and 3 OR 4 but NOT 5 OR 6
You can do this with group by and having. The basic idea is:
select ti.id_trans
from trans_item ti
group by ti.id_trans
having sum(ti.id_perf in (1, 2)) > 0 and
sum(ti.id_perf in (3, 4)) > 0 and
sum(ti.id_perf in (5, 6)) = 0;
Each condition in the having clause checks a row for the particular ids. The > 0 means they exist for transaction. The = 0 means they do not.
If you want additional columns from other tables, you can join back to this result set.
I think I have a solution. If I combine the ids for all perfs and group all results by the trans_item.id I can get a list that has duplicates. I then convert them into a php multidimensional array and exclude / include based on the ids for each requirement finding the duplicates that way. Any other suggestions are welcome

Preserve from splitting results

Is there any possible way to SELECT from MYSQL database and preserve from splitting results? I'd like to get all the data from previous day, but it'll be too much, but I also cannot split results:
Select all with certain limit, but do not split (by certain value, i.e. user_id) onto separate results.
EXAMPLE
SELECT
ti.id, ti.date, ti.duedate, ti.datepaid,
tii.invoiceid, tii.userid,
tc.postcode, tc.country,
(SELECT GROUP_CONCAT(value) FROM custom WHERE relid=tc.id) AS vatid
FROM invoices ti
LEFT JOIN invoiceitems tii
ON tii.invoiceid=ti.id
LEFT JOIN clients tc
ON tc.id=tii.userid
WHERE ti.status='Paid'
AND ti.nullmo_no IS NULL
ORDER BY tii.userid AND tii.id
Now I get all the results, but I need to split them without breaking userid. For example one SELECT returns 20 results, because there were 15 invoices for user 1, and 5 invoices for user 2, then the next call returns the rest, also with a limit, but not breaking user related group of results:
SELECT
part 1 (all from user 1, all from user 2)
part 2 (all from user 3, all from user 4)
Can this be done in one select statement?
id = 1,2,3,4,5,6,7,8,9,10
name = n1, n2, n3, n4, n5, n6, n7, n8, n9, n10
user_id = 1, 1, 1, 2, 2, 2, 3, 3, 4, 5 // split but not divide
content = c1,c2,c3,c4,c5,c6,c7,c8,c9,c10
date = yesterday, yesterday, yesterday, yesterday, yesterday, yesterday, yesterday, yesterday, yesterday, yesterday
The deal is to select all of them, with a limit, but not to split user_id, so: 1. All from yesterday 2. LIMIT if per one or more user_id's there are more results than LIMIT So the limit would be determined by the number of results.

SQL - select first in value set by priority?

I'm fairly inexperienced in SQL and this seems like it must be an easy task, but I'm not sure how to go about it.
Basically I want to select a single row from table A where field "someField" is in a pre-determined set "someSet", but I want it to look for each value in the set individually. For example, let's say "someSet" contains 5, 6, 9, 3. I would use a query similar to this:
SELECT * FROM A WHERE someField IN (5, 6, 9, 3) LIMIT 1
However, I want it to look for 5 first, then 6, then 9, then finally 3 if no rows have been found yet. Written as separate queries it'd look like this:
SELECT * FROM A WHERE someField = 5 LIMIT 1
(if no results returned)
SELECT * FROM A WHERE someField = 6 LIMIT 1
(if no results returned)
SELECT * FROM A WHERE someField = 9 LIMIT 1
(if no results returned)
SELECT * FROM A WHERE someField = 3 LIMIT 1
Obviously using 4 queries (theoretically infinite queries) isn't very elegant, is there a way to make this into a single query?
You can do
SELECT * FROM A WHERE someField IN (5, 6, 9, 3)
ORDER BY FIELD( someField, 5, 6, 9, 3)
LIMIT 1