MS Access SQL:选择与IN子句顺序相同的行
我知道这个问题已经被问了好几次,我已经阅读了所有的答案,但是没有一个能完全解决我的问题 我正在从mySQL数据库切换到MS Access数据库。在这两种情况下,我都使用php脚本连接到数据库并执行SQL查询 我需要为我在mySQL上执行的查询找到合适的替代品。 我想:MS Access SQL:选择与IN子句顺序相同的行,sql,sql-server,ms-access,sql-order-by,in-clause,Sql,Sql Server,Ms Access,Sql Order By,In Clause,我知道这个问题已经被问了好几次,我已经阅读了所有的答案,但是没有一个能完全解决我的问题 我正在从mySQL数据库切换到MS Access数据库。在这两种情况下,我都使用php脚本连接到数据库并执行SQL查询 我需要为我在mySQL上执行的查询找到合适的替代品。 我想: 执行第一次查询,并根据其中一列按字母顺序排列记录 构建一个ID列表,该列表反映以前的字母顺序 使用IN子句执行第二个查询,IN子句应用于IDs的列表并按此列表排序 在mySQL中,我使用以下方式执行最后一个查询: SELECT n
SELECT name FROM users WHERE id IN ($name_ids) ORDER BY FIND_IN_SET(id,'$name_ids')
由于FIND_IN_SET
仅在mySQL中可用,而CHARINDEX
和PATINDEX
在我的php脚本中不可用,我如何实现这一点
我知道我可以写这样的东西:
SELECT name
FROM users
WHERE id IN ($name_ids)
ORDER BY CASE id
WHEN ... THEN 1
WHEN ... THEN 2
WHEN ... THEN 3
WHEN ... THEN 4
END
但是你必须考虑到:
- IDs的列表具有可变的长度和元素,因为它取决于第一个查询
- 该列表可以轻松地包含数千个元素
ORDER。。。什么时候…
声明?
有没有更好的方法,因为我的ID列表可能很大
更新:我执行两个单独的查询,因为我需要访问两个不同的表。
数据库不是很简单,所以我试着举个例子:
假设我有一个包含用户列表的表和一个包含每个用户书架上所有书籍的表
因为dabase是在mySQL中设计的,所以对于每个图书记录,我都将用户id存储在books表中,以便在用户和图书之间建立关系
假设现在我想获得所有用户的列表,这些用户的书籍标题以字母“a”开头,我想根据书籍的字母顺序对用户进行排序。
我就是这么做的:
希望这能澄清我的需要。如果我理解正确,您试图以与指定ID值相同的顺序获取一组信息。有一种黑客可以使用XML和交叉应用将列表转换为表。这可以与ROW_NUMBER函数结合使用以生成排序顺序。请参阅下面的代码:
CREATE FUNCTION [dbo].[GetNvarcharsFromXmlArray]
(
@Strings xml = N'<ArrayOfStrings/>'
)
RETURNS TABLE
AS
RETURN
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RowNumber, Strings.String.value('.', 'nvarchar(MAX)') AS String
FROM @Strings.nodes('/ArrayOfStrings/string/text()') AS Strings(String)
)
请注意,如果您需要的话,让函数返回一个整数表是非常简单的重写
您可以了解如何更好地理解在SQL查询中使用XML。另外,请参见。如果我理解正确,您正试图以与指定ID值相同的顺序获取一组信息。有一种黑客可以使用XML和交叉应用将列表转换为表。这可以与ROW_NUMBER函数结合使用以生成排序顺序。请参阅下面的代码:
CREATE FUNCTION [dbo].[GetNvarcharsFromXmlArray]
(
@Strings xml = N'<ArrayOfStrings/>'
)
RETURNS TABLE
AS
RETURN
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RowNumber, Strings.String.value('.', 'nvarchar(MAX)') AS String
FROM @Strings.nodes('/ArrayOfStrings/string/text()') AS Strings(String)
)
请注意,如果您需要的话,让函数返回一个整数表是非常简单的重写
您可以了解如何更好地理解在SQL查询中使用XML。另外,请参见。您必须使用维护订单的用户定义函数,然后按该列进行订单。例如:
CREATE FUNCTION dbo.SplitList
(
@List VARCHAR(8000)
)
RETURNS TABLE
AS
RETURN
(
SELECT DISTINCT
[Rank],
[Value] = CONVERT(INT, LTRIM(RTRIM(SUBSTRING(@List, [Rank],
CHARINDEX(',', @List + ',', [Rank]) - [Rank]))))
FROM
(
SELECT TOP (8000) [Rank] = ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS n
WHERE [Rank] <= LEN(@List)
AND SUBSTRING(',' + @List, [Rank], 1) = ','
);
GO
根据SQL语句的构造方式,您可能必须使用单引号(dbo.SplitList(“$name\u id”)
)将$name\u id
括起来。您可能想考虑使用存储过程,而不是在PHP中构建此查询。
您也可以考虑跳过MS Access作为跳转点。为什么不让PHP直接与SQL Server通信?
您必须使用一个用户定义的函数来维护顺序,然后按该列排序。例如:CREATE FUNCTION dbo.SplitList
(
@List VARCHAR(8000)
)
RETURNS TABLE
AS
RETURN
(
SELECT DISTINCT
[Rank],
[Value] = CONVERT(INT, LTRIM(RTRIM(SUBSTRING(@List, [Rank],
CHARINDEX(',', @List + ',', [Rank]) - [Rank]))))
FROM
(
SELECT TOP (8000) [Rank] = ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS n
WHERE [Rank] <= LEN(@List)
AND SUBSTRING(',' + @List, [Rank], 1) = ','
);
GO
根据SQL语句的构造方式,您可能必须使用单引号(dbo.SplitList(“$name\u id”)
)将$name\u id
括起来。您可能想考虑使用存储过程,而不是在PHP中构建此查询。
您也可以考虑跳过MS Access作为跳转点。为什么不让PHP直接与SQL Server通信呢?
听起来您需要一个加入…
这应该是可行的,尽管可能需要将其转换为Access语法(这显然是微妙的不同):
我不知道你为什么要切换到接入,尽管我听说近年来接入技术有所改善。不过,我想我更喜欢几乎任何其他RDBMS。从事物的声音来看,您的模式可能会经受一些调整。听起来您需要一个加入。
这应该是可行的,尽管可能需要将其转换为Access语法(这显然是微妙的不同):
我不知道你为什么要切换到接入,尽管我听说近年来接入技术有所改善。不过,我想我更喜欢几乎任何其他RDBMS。从事情的声音来看,您的模式可能会经受一些调整。这些查询必须是两个独立的查询吗?第一个看起来像什么?通过组合它们,或者重新考虑它们之间的连接方式,事情完全有可能得到改进。它们是独立的查询,因为它们是在两个独立的表上执行的。我将编辑该问题以澄清这一方面,这两个表不能JOIN
ed?第一个表的名称和布局是什么?@X-Zero:我用一个例子更新了这个问题。可能有一种更简单的方法来构建数据库,但我在SQL和数据库方面的经验很少
CREATE FUNCTION dbo.SplitList
(
@List VARCHAR(8000)
)
RETURNS TABLE
AS
RETURN
(
SELECT DISTINCT
[Rank],
[Value] = CONVERT(INT, LTRIM(RTRIM(SUBSTRING(@List, [Rank],
CHARINDEX(',', @List + ',', [Rank]) - [Rank]))))
FROM
(
SELECT TOP (8000) [Rank] = ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS n
WHERE [Rank] <= LEN(@List)
AND SUBSTRING(',' + @List, [Rank], 1) = ','
);
GO
SELECT u.name
FROM dbo.users AS u
INNER JOIN dbo.SplitList($name_ids) AS s
ON u.id = s.Value
ORDER BY s.[Rank];
SELECT b.name, a.title
FROM book as a
JOIN user as b
ON b.id = a.userId
WHERE SUBSTRING(LOWER(a.title), 1, 1) = 'a'
ORDER by a.title