如何构造MS Access Query,使用子查询的结果进行相互比较

时间:2013-04-04 13:55:05

标签: sql ms-access

将MS Access 2010与链接表一起使用到SQL Server 2005.链接表有5列:

PName - STRING
OName - STRING
FName - STRING  
Readable - BOOLEAN  
Editable - BOOLEAN  

示例数据:

PName   FName                readable   editable
UK      Case.First_Name         0       0
UK      Case.Last_Name          0       0
UK      Case.Middle_Initial     0       0
UK      Case.Phone_Number       0       0
UK      Case.Username           -1      -1
USA     Case.First_Name         0       0
USA     Case.Last_Name          0       0
USA     Case.Middle_Initial     0       0
USA     Case.Phone_Number       0       0
USA     Case.Username           -1      -1

想要创建一个查询,该查询将返回PName中所有FName的列表,但只有在所有PName中的Readable值不同或者所有PName中的Editable值不同时才显示FName。

示例输出:

                      UK           USA
                   Edit|Read    EDIT|Read
Case.First_Name    T   |  T       F | T
Case.UserName      F   |  F       F | T

在上面,“Case.First_Name”可以由英国编辑,但不是由美国编辑,因此我希望看到这一行

Case.UserName不是英国可读的,而是美国的,因此我希望看到这一行

不应该输出什么:

                      UK           USA
                   Edit|Read    EDIT|Read
Case.First_Name    T   |  T       T | T
Case.UserName      F   |  F       F | F

上述两行对英国和美国都具有相同的可读性和可编辑性权限,因此我不希望看到这些行。

以下查询将获取我需要的原始数据,然后我可以将其转换为数据透视表:

SELECT PName, FName, Readable, Editable
FROM ProfileFLS
WHERE PName Like "U*";

然后将其导出到excel并使用If语句。

请注意,配置文件的数量是动态的。

感谢您的帮助

最新的SQL:

SQL如下,我也尝试将=“True”更改为0

TRANSFORM Sum(IIf(dbo_ProfileFLS.readable="TRUE","Read_True","Read_False")) AS Readable
SELECT dbo_ProfileFLS.fieldname
FROM dbo_ProfileFLS
WHERE (((dbo_ProfileFLS.objectname)="Case") AND ((dbo_ProfileFLS.Profile) Like "UK*"))
GROUP BY dbo_ProfileFLS.fieldname, dbo_ProfileFLS.readable
PIVOT dbo_ProfileFLS.Profile;

2 个答案:

答案 0 :(得分:2)

感谢您修改问题。事情现在更清楚了。

让我们首先调整您的样本数据,以便我们获得一些实际结果。

PName   FName               readable    editable
UK      Case.First_Name     0           -1
UK      Case.Last_Name      0           0
UK      Case.Middle_Initial 0           0
UK      Case.Phone_Number   0           0
UK      Case.Username       -1          -1
USA     Case.First_Name     0           0
USA     Case.Last_Name      0           0
USA     Case.Middle_Initial -1          0
USA     Case.Phone_Number   0           0
USA     Case.Username       -1          -1
Canada  Case.First_Name     0           0
Canada  Case.Last_Name      0           -1
Canada  Case.Middle_Initial 0           0
Canada  Case.Phone_Number   0           0
Canada  Case.Username       0           0

现在考虑以下查询。这是一个自我联接,在[FName]上查找匹配,在[可读] OR [可编辑]上查找不匹配:

SELECT p1.FName, 
    p1.PName AS PName1, p1.readable AS read1, p1.editable AS edit1,
    p2.PName AS PName2, p2.readable AS read2, p2.editable AS edit2
FROM permissionsTbl p1 INNER JOIN permissionsTbl p2
    ON p1.FName=p2.FName 
        AND (p1.readable<>p2.readable OR p1.editable<>p2.editable)
ORDER BY 1, 2 ;

返回

FName               PName1  read1   edit1   PName2  read2   edit2
Case.First_Name     Canada  0       0       UK      0       -1
Case.First_Name     UK      0       -1      Canada  0       0
Case.First_Name     UK      0       -1      USA     0       0
Case.First_Name     USA     0       0       UK      0       -1
Case.Last_Name      Canada  0       -1      USA     0       0
Case.Last_Name      Canada  0       -1      UK      0       0
Case.Last_Name      UK      0       0       Canada  0       -1
Case.Last_Name      USA     0       0       Canada  0       -1
Case.Middle_Initial Canada  0       0       USA     -1      0
Case.Middle_Initial UK      0       0       USA     -1      0
Case.Middle_Initial USA     -1      0       UK      0       0
Case.Middle_Initial USA     -1      0       Canada  0       0
Case.Username       Canada  0       0       USA     -1      -1
Case.Username       Canada  0       0       UK      -1      -1
Case.Username       UK      -1      -1      Canada  0       0
Case.Username       USA     -1      -1      Canada  0       0

并向我们展示了读取或编辑权限不匹配的每种情况。

现在我们将调整一下,为我们提供上面列表中出现的[FName]值的DISTINCT列表......

SELECT DISTINCT p1.FName 
FROM permissionsTbl p1 INNER JOIN permissionsTbl p2
    ON p1.FName=p2.FName 
        AND (p1.readable<>p2.readable OR p1.editable<>p2.editable) ;

...并将其用作子查询以从原始表中提取这些FName行

SELECT * FROM permissionsTbl
WHERE FName IN
(
    SELECT DISTINCT p1.FName 
    FROM permissionsTbl p1 INNER JOIN permissionsTbl p2
        ON p1.FName=p2.FName 
            AND (p1.readable<>p2.readable OR p1.editable<>p2.editable)
) ;

...返回......

PName   FName               readable    editable
UK      Case.First_Name     0           -1
UK      Case.Last_Name      0           0
UK      Case.Middle_Initial 0           0
UK      Case.Username       -1          -1
USA     Case.First_Name     0           0
USA     Case.Last_Name      0           0
USA     Case.Middle_Initial -1          0
USA     Case.Username       -1          -1
Canada  Case.First_Name     0           0
Canada  Case.Last_Name      0           -1
Canada  Case.Middle_Initial 0           0
Canada  Case.Username       0           0

...并且可用于为下游流程提供信息。

答案 1 :(得分:0)

您可以使用MS Access向导创建交叉表查询,也可以使用PIVOT创建SQL-Passthrough查询以使SQL Server进行处理。

编辑:根据修订后的问题添加以下内容

您可以在不使用交叉表的情况下离开。这取决于您的查询需要多么灵活,或者您是否可以动态构建查询。对于上面的英国/美国示例,您可以使用:

SELECT dbo_ProfileFLS.FName,
       dbo_ProfileFLS.Readable AS [UK Read], 
       dbo_ProfileFLS.Editable AS [UK Edit],
       dbo_ProfileFLS_1.Readable AS [USA Read],
       dbo_ProfileFLS_1.Editable AS [USA Edit]
FROM   dbo_ProfileFLS
INNER JOIN dbo_ProfileFLS AS dbo_ProfileFLS_1
ON     dbo_ProfileFLS.FName = dbo_ProfileFLS_1.FName
WHERE  dbo_ProfileFLS.PName="UK"
  AND  dbo_ProfileFLS_1.PName="USA" 
  AND  (dbo_ProfileFLS.Readable<>[dbo_ProfileFLS_1].[Readable]
       OR dbo_ProfileFLS.Editable<>[dbo_ProfileFLS_1].[Editable]);

如果您真的想使用交叉表,那么问题是您只能使用值列(如您所见)。您可以通过连接可读字段和可编辑字段来解决此问题。由于交叉表使用Group By但实际上您需要普通值,因此需要使用聚合函数First。例如:

TRANSFORM First(Readable & " | " & Editable) AS ReadEdit
SELECT dbo_ProfileFLS.FName
FROM dbo_ProfileFLS
GROUP BY dbo_ProfileFLS.FName
PIVOT dbo_ProfileFLS.PName & " Read | Edit";

当然,此查询采用完整的表格。要仅获取正确的值,您需要将第一个查询的变体用作过滤器:

SELECT dbo_ProfileFLS.ID AS UK_ID,
       dbo_ProfileFLS_1.ID AS USA_ID
FROM   dbo_ProfileFLS
INNER JOIN dbo_ProfileFLS AS dbo_ProfileFLS_1 
ON     dbo_ProfileFLS.FName = dbo_ProfileFLS_1.FName
WHERE  dbo_ProfileFLS.PName="UK"
  AND  dbo_ProfileFLS_1.PName="USA" 
  AND  (dbo_ProfileFLS.Readable<>[dbo_ProfileFLS_1].[Readable]
       OR dbo_ProfileFLS.Editable<>[dbo_ProfileFLS_1].[Editable]);

如果将其命名为crosstabFilter,则将其与dbo_ProfileFLS交叉连接并使用以下条件:

WHERE crosstabFilter.UK_ID=ID OR crosstabFilter.USA_ID=ID