我在MySQL数据库中有一个名为products
的表。 products
看起来像这样:
id name din strength active deleted
1 APA TEST 00246374 25 1 0
4 APA BOB 00246375 50 1 0
5 APA TIRE 00246888 50 1 0
7 APA ROT 00521414 100 1 0
9 APA APA 01142124 100 1 0
6 APA CODE 00121212 150 1 0
8 APA SERV 00011145 600 1 0
显然,我遗漏了几个对我的问题不重要的专栏。当我查询这个表时,我将按几个不同的列中的一个进行排序(用户界面允许单个用户更改排序列和顺序),我可能有一个搜索子句,在这种情况下我会做一个LIKE子句名称和DIN。
我想知道的是,鉴于排序信息和搜索信息,以及特定产品的ID(假设我搜索了004,返回了3个结果,我正在查看其中一个),我怎么能得到下一个和以前的产品?
我需要这样做,因为如果用户在搜索和排序结果后点击编辑/查看其中一个产品,他们希望能够循环浏览结果而无需转到上一页。
在SQL中有没有一种好的有效方法,或者我最好使用PHP?任何想法也欢迎。
目前正在使用此SQL查询,如果我按strength
列排序,则会出现问题,因为存在重复值
SELECT T.*
FROM `wp_products` T
INNER JOIN `wp_products` curr on curr.id = 38
AND ((T.strength = curr.strength and T.id < curr.id)
OR (T.strength > curr.strength))
WHERE T.active = 1 AND T.deleted = 0 AND (T.name LIKE '%%' OR T.din LIKE '%%')
ORDER BY T.strength ASC, T.id ASC
LIMIT 1
我的PHP代码(使用WordPress)(旨在获取下一个项目)
$sql = 'SELECT T.*
FROM `' . $wpdb->prefix . 'apsi_products` T
INNER JOIN `' . $wpdb->prefix . 'apsi_products` curr on curr.id = ' . $item->id . '
AND ((T.' . $wpdb->escape( $query['orderby'] ) . ' = curr.' . $wpdb->escape( $query['orderby'] ) . ' and T.id > curr.id)
OR (T.' . $wpdb->escape( $query['orderby'] ) . ' > curr.' . $wpdb->escape( $query['orderby'] ) . '))
WHERE T.active = 1 AND T.deleted = 0 AND (T.name LIKE \'%' . $query['where'] . '%\' OR T.din LIKE \'%' . $query['where'] . '%\')
ORDER BY T.' . $wpdb->escape( $query['orderby'] ) . ' ' . $query['order'] . ', T.id ASC
LIMIT 1;';
答案 0 :(得分:5)
您需要引用当前记录,然后根据已排序的列逐步查找下一条记录。以下示例假定它已按
排序ORDER BY Active, DIN, NAME
首先:
SELECT *
FROM TABLE
WHERE NAME LIKE '%X%' AND DIN LIKE '%%'
ORDER BY Active, DIN, Name
LIMIT 1;
下一步:( 确保将CURR.ID = 6
和AND-OR与适当的括号分开! )
SELECT *
FROM TABLE T
INNER JOIN TABLE CURR ON CURR.ID = 6 # the current ID being viewed
AND ((T.Active = Curr.Active AND T.DIN = Curr.DIN AND T.NAME > Curr.Name)
OR (T.Active = Curr.Active AND T.DIN > Curr.DIN)
OR T.Active > Curr.Active)
WHERE T.NAME LIKE '%X%' AND T.DIN LIKE '%%'
ORDER BY T.Active, T.DIN, T.Name
LIMIT 1;
下面提供的工作样本
create table products
(ID int, SEED int, NAME varchar(20), DIN varchar(10), ACTIVE int, DELETED int);
insert products values
(1, 0, 'Product #1', '004812', 1, 0),
(2, 0, 'Product #2', '004942', 0, 0),
(3, 0, 'Product #3', '004966', 1, 0),
(4, 0, 'Product #4', '007437', 1, 1),
(5, 2, 'Product #2', '004944', 0, 0),
(6, 2, 'Product #2', '004944', 1, 0);
SELECT *
FROM products
WHERE active = 1 AND deleted = 0
ORDER BY din DESC, ID desc;
Output:
"ID";"SEED";"NAME";"DIN";"ACTIVE";"DELETED"
"3";"0";"Product #3";"004966";"1";"0"
"6";"2";"Product #2";"004944";"1";"0"
"1";"0";"Product #1";"004812";"1";"0"
如果current是ID = 6的行,则可以使用
检索下一条记录SELECT T.*
FROM products T
INNER JOIN products curr on curr.ID = 6
AND ((T.din = curr.din and T.ID > curr.ID)
OR (T.din < curr.din))
WHERE T.active = 1 AND T.deleted = 0
ORDER BY T.din DESC, T.ID ASC
LIMIT 1;
答案 1 :(得分:1)
如果没有像memcached这样的持久性缓存层,您可以在其中存储结果并在不重新发布查询的情况下获取结果,一个简单的解决方案就是在mysql中启用query cache。这样,如果缓存没有从其他查询中失效,当您重新发出查询时,拉动结果的成本将会降低
答案 2 :(得分:1)
对于每个显示的结果,请使用相应的ID设置 next 和 previous 链接。
无法从详细信息视图更改排序顺序。
答案 3 :(得分:0)
有趣的问题。我不认为你可以在一个查询中做到这一点,但你可以用三个来完成它。
第一个查询拉出答案行。诀窍是保持他们排序的列的值。我们假设这是“SortedColumn”,值为“M”。假设您获得的行的ID为10。
你的第二个查询与第一个查询相同,但是会是“top 1”并且会添加到where子句“... and sortedColumn&gt; ='M'和id&lt;&gt; 10”你下一排。您可能希望返回10行并保留它们以防止反复执行此操作。
要获取上一个,请将您的排序切换为降序,并添加的where子句为“...和sortColumn&lt; ='M',id&lt;&gt; 10”。这可以获得前一行。同样,10行可能对您的用户更有用。
希望这会有所帮助。