2012-03-23 21 views
0

我知道这个问题已被多次询问,并且我已经阅读了所有答案,但没有一个似乎完全解决了我的问题。MS Access SQL:选择具有与IN子句相同顺序的行

我从mySQL数据库切换到MS Access数据库。在这两种情况下,我使用php脚本连接到数据库并执行SQL查询。

我需要找到一个合适的替代我曾经在mySQL上执行的查询。 我想:

  1. 执行按字母顺序根据列
  2. 之一的第一查询和订单记录建立ID的列表,它反映的是前字母顺序
  3. 与IN子句进行第二次查询与ID列表一起使用并按此列表排序。

在MySQL中我用来执行的最后一个查询是这样的:

SELECT name FROM users WHERE id IN ($name_ids) ORDER BY FIND_IN_SET(id,'$name_ids') 

由于FIND_IN_SET仅提供MySQL的数据和CHARINDEXPATINDEX不能从我的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 

,但你必须考虑到:

  • 的ID名单具有可变长度和元素,因为它取决于第一查询
  • 该列表可以很容易地包含数千个元素

你有没有对此有何暗示? 有没有办法以编程方式构造ORDER BY CASE ... WHEN ...陈述? 由于我的ID列表可能很大,是否有更好的方法?

UPDATE:我执行两个分离的查询,因为我需要访问两个不同的表。 数据库并不是非常简单,所以我试着举一个例子: 假设我有一个表,其中包含一个用户列表和一个表,其中包含每个用户在其书架中的所有书籍。

由于dabase是在mySQL中设计的,对于每本书籍记录,我都将user_id存储在books表中以便在用户和书籍之间建立关系。

现在假设我想获得所有拥有以字母“a”开头的书名的用户的列表,并且我想根据书籍的字母顺序来订购用户。 这是我做的:

  1. 执行第一查询以查找所有以字母“A”开头的书籍和排序的字母顺序
  2. 创建的user_id的列表,它应该反映书的字母顺序
  3. users表中进行查询,以找出用户名和它们与USER_ID列表排序书具有所需的排序

希望澄清一下我需要什么。

+0

这些必须是两个单独的查询吗?第一个看起来像什么?将它们结合起来或者重新考虑它们之间的联系是完全可能的。 – 2012-03-23 23:11:34

+0

他们是单独的查询,因为在两个单独的表上执行。我会编辑这个问题来澄清这个问题 – Andrea3000 2012-03-23 23:20:33

+0

什么,而且这两个表格不能'JOIN'ed?第一个表的名称和布局是什么? – 2012-03-23 23:29:11

回答

1

这听起来像你需要一个JOIN ...
应该工作,尽管它可能需要被翻译成访问语法(这显然是微妙的不同):

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 

我不不知道为什么你要切换到Access,尽管我听说近年来它一直在改进。不过,我认为我更喜欢其他任何关系型数据库。从事物的声音来看,你的模式可能会做一些调整。

+0

这不是我的决定,我们将我们的网站移动到新位置的新服务器,并且此新服务器场仅提供Access作为数据库支持。 我更喜欢mySQL毫无疑问。关于您的解决方案,我无法获得与mySQL实现相同的结果,因为我无法使用“JOIN”过滤重复记录。 – Andrea3000 2012-04-04 12:14:03

+0

鉴于元组[b.name','a.title']在源数据中应该是唯一的(主要是),你期望什么是唯一的? – 2012-04-04 16:39:11

2

如果我理解正确,您试图按照指定ID值的相同顺序获取一组信息。有一种黑客可以使用XML和CROSS APPLY将列表转换为表格。这可以与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) 
) 

与结构如下功能:

<ArrayOfStrings> 
    <string>myvalue1</string> 
    <string>myvalue2</string> 
</ArrayOfStrings> 

这也是相同的格式.NET XML序列化字符串数组。

如果你想传递一个逗号分隔的列表,你可以简单地使用:

CREATE FUNCTION [dbo].[GetNvarcharsCSV] 
( 
    @CommaSeparatedStrings nvarchar(MAX) = N'' 
) 
RETURNS TABLE 
AS 
RETURN 
(
     DECLARE @Strings xml 
     SET @Strings = CONVERT(xml, N'<ArrayOfStrings><string>' + REPLACE(@CommaSeperatedStrings, ',', N'</string><string>') + N'</string></ArrayOfStrings>') 

    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) 
) 

这使得您的查询:

SELECT name 
FROM users 
INNER JOIN dbo.GetNvarcharsCSV(@name_ids) AS IDList ON users.ID = IDList.String 
ORDER BY RowNumber 

请注意,这是一个非常简单的重写,使函数返回一个整数表,如果这是你所需要的。

您可以看到xml Data Type Methods以更好地理解您可以在SQL查询中使用XML做什么。另请参阅ROW_NUMBER (Transact-SQL)

+0

谢谢你的建议。我是SQL,VBA和.NET中的真正的noob,所以我很难完全理解你的解决方案,我不认为我知道它是因为我试图实现它,但它不起作用。无论如何,我已经找到了一个更易于理解的解决方案,我更愿意利用它。不管怎样,谢谢你! – Andrea3000 2012-03-25 14:30:20

+0

按照承诺,我回来了,并更新了答案,以便更完整。我希望现在可以清楚地看到整个事情。 – JamieSee 2012-03-27 16:22:44

0

您将不得不使用用户定义的函数来维护订单,然后按该列进行排序。例如:

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]; 

您可能必须围绕$name_ids与依赖于SQL语句是如何构造的单引号(dbo.SplitList('$name_ids'))。您可能需要考虑使用存储过程,而不是在PHP中构建此查询。

你也可以考虑跳过MS-Access作为跳频点。为什么不直接让PHP与SQL Server直接通信?

+0

您的解决方案使用了我没有的'CHARINDEX',是否有相当于它的?我必须使用与ADODB连接的MS Access数据库,因为我的托管服务需要额外的费用来直接处理SQL数据库 – Andrea3000 2012-03-24 11:35:08

+0

@ Andrea3000 - 如果charindex不可用,可能您没有使用sql server(Transact SQL)。 – JeffO 2012-03-24 12:13:55

+0

我再次建议使用存储过程并直接从PHP调用存储过程。如果您试图将此查询传递给Access,那么您将难以制定出您想要的查询,可以通过MS-Access进行解析并由SQL Server执行。 – 2012-03-24 12:30:01