【问题标题】:Combining 2 queries - getting column names in one and using results in another query结合 2 个查询 - 在一个查询中获取列名并在另一个查询中使用结果
【发布时间】:2015-09-12 13:26:40
【问题描述】:

构建我的第一个 Microsoft Access SQL 查询。这不应该这么难!
我有 2 张桌子:

属于GroupA 的用户已登录。我只想向他显示GroupA 分配到的那些Data 表行和列,如下所示:

+--------+--------+--------+
| Group  |  Data3 | Data4  |
+--------+--------+--------+
| GroupA |   9    |   4    | 
| GroupA |   1    |   5    |
+--------+--------+--------+

我尝试了这个愚蠢的选择:

SELECT (select Data from AccessRights where GroupA = "y")
FROM Data
WHERE Data.Group = "GroupA";

【问题讨论】:

  • 那么,您能否告诉我们答案必须满足哪些标准才能被您接受为答案?如果您需要运行 VBA 代码来解决问题,或者您只是与查询设计器一起工作,您是否可以接受?
  • 我宁愿只在 SQL 中进行。但是如果不改变我的数据结构似乎是不可能的。所以VBA也不错。
  • 这个问题的根源在于架构。我不确定您要解决什么问题,但此表/列设计并不好。这就是您遇到 SQL 问题的原因。如果将“y”分配给 AccessRights 表的 GroupA 和 GroupB 列中的所有值会发生什么?我认为您正在尝试构建的是基于角色的身份验证系统。为此,您的表格会有所不同。
  • @itsben - 你完全正确地理解了我正在尝试构建的内容。但我不知道应该如何设计表格。所以我只是即兴创作并以此为基础。如果您有任何关于表在基于角色的身份验证系统中的外观的良好参考/示例,我很乐意了解它。但至少现在我拥有我所拥有的。我已经实现了一个 SQL-VBA 解决方案来完成这项任务。和what was offered by shA.t很像
  • 这种手工构建的身份验证系统有一个常见的陷阱,新 Access 用户通常不知道:用户可以轻松绕过您的保护。例如,他们可以在启动 Access 时按 SHIFT 以绕过您的启动代码并让所有数据库对象可用。您可以通过 Access 设置和程序代码来保护自己免受这种情况的影响,但任何用户仍然可以在没有您的应用程序的情况下启动 Access(然后获得所有可用数据)。因此,如果您需要真正的安全性,请至少使用 Access 提供的身份验证系统(遗憾的是不能保护单个列)。

标签: sql ms-access select


【解决方案1】:

只旋转您的数据表并添加一个名为 data 的列可能会更好。对访问权限执行相同操作。

你的数据表看起来像这样:

Group, Data, Value
Groupa,Data1,1
Groupb,Data2,7
...

这样的访问权限:

Data, Group, Valid
Data1, GroupA, Y
Data2, GroupA, N

然后您可以将两个表连接在一起并根据需要进行过滤。

Select * 
FROM Data D 
  JOIN AccessRights A 
     on D.data = A.data and D.Group = A.Group
WHERE A.Valid = 'Y' 
      and D.Group = 'GroupA'

【讨论】:

  • 感谢您的建议。我考虑过旋转表格,但我仍然有这个选项。但是,我仍然想相信应该有某种方法可以在不更改任何内容的情况下获得结果。我仍然认为任何 RDBMS 都是灵活的,我不想这么轻易地失去这种信念...... :)
  • 这个答案显示了 RDBMS 的灵活性。您的方式是与关系数据库的工作方式作斗争。访问在混合数据和演示方面更加宽容,但通常要使用您的表格结构,您会选择行来整理演示部分中的动态列。请注意,这种方法的缺点是所有数据都必须具有相同的类型。
【解决方案2】:

我使用这个查询:

SELECT 
    Data.[Group], 
    IIf((SELECT GroupA FROM AccessRights WHERE Data = "Data1")="y",[Data1],Null) AS Data_1, 
    IIf((SELECT GroupA FROM AccessRights WHERE Data = "Data2")="y",[Data2],Null) AS Data_2, 
    IIf((SELECT GroupA FROM AccessRights WHERE Data = "Data3")="y",[Data3],Null) AS Data_3, 
    IIf((SELECT GroupA FROM AccessRights WHERE Data = "Data4")="y",[Data4],Null) AS Data_4
FROM 
    Data
WHERE 
    ((Data.[Group])="GroupA");

对于这个结果:

Group   | Data_1 | Data_2 | Data_3 | Data_4
--------+--------+--------+--------+--------
GroupA  |        |        | 9      | 4
GroupA  |        |        | 1      | 5

我只是隐藏了Data1Data2 的值。


如果你真的想隐藏你的列,你需要使用 VBA,我创建了一个 VBA 函数,它将根据你的组给出最终的查询字符串:

Function myQuery(groupName As String) As String
    Dim strResult As String
    Dim rs As Recordset
    Dim i As Integer

    strResult = "SELECT [DATA].[Group]"

    Set rs = CurrentDb.OpenRecordset("SELECT [Data], [" & groupName & "] FROM AccessRights WHERE [" & groupName & "] = ""y""")

    For i = 0 To rs.RecordCount
        strResult = strResult & "," & rs.Fields("Data").Value
        rs.MoveNext
    Next i

    strResult = strResult & " FROM [Data] WHERE ((Data.[Group])=""" & groupName & """)"

    myQuery = strResult
End Function

例如; myQuery("GroupA") 将是

SELECT [DATA].[Group],Data3,Data4 FROM [Data] WHERE ((Data.[Group])="GroupA")

【讨论】:

  • 为什么不关闭记录集并在函数结束时将其设置为空?它是否自动关闭/设置为空?
  • @ZygD 是的,它是一个局部变量。最好在结束前关闭它。
  • 到目前为止我最喜欢这个答案,因为它不需要我改变我的数据结构。
【解决方案3】:

@ZygD,这是架构:

USER
user_id int primary key auto_increment
user_name varchar(100)
password varchar(100)

GROUP
group_id int primary key auto_increment
group_name varchar(100)

DATA
data_id int primary key auto_increment 
data_name varchar(100)

USER_GROUP
user_id int
group_id int


GROUP_DATA
group_id
data_id

我会解释的。首先你定义你的“对象类型”。你有一个 USER、GROUP 和你所谓的 DATA。除此之外,使用另一个词代替 DATA 可能是个好主意。使用类似 ITEM 的东西,甚至是 DATAITEM。对于这个例子,我将使用 DATA。好的,所以这些表中的每一个都有一个整数值,因为它是主键。主键是表中记录的唯一标识符,它会自动递增。您可以在 Access 中进行设置。

现在您已经有了三个对象类型表,您需要所谓的“连接表”来描述“对象类型”表之间的关系。 USER_GROUP 表表明一个用户可以属于一个或多个组。例如,如果用户 1 同时属于组 1 和组 2,那么您将在 USER_GROUP 表中有两条记录来描述这些关系。第一行是 1,1,第二行是 1,2。

GROUP_DATA 表描述了 GROUP 和 DATA 之间的关系。例如,组 1 可以访问数据 2 和数据 3。同样,您将在 GROUP_DATA 表中有两行来描述这些关系。第一行是 1,2,第二行是 1,3。

现在,因为用户 1 属于组 1,所以用户 1 将可以访问数据 2 和 3。然后您的 SQL 就变得简单了:

// Authenticate the user with user_name and password:
select @user_id = a.user_id from user a where a.user_name = @user_name and a.password = @password

// Get DATA by user_id
select c.data_id, c.data_name from user a join group b on a.user_id = b.user_id join data c on b.data_id = c.data_id where a.user_id = @user_id

【讨论】:

  • 感谢您的回答。太糟糕了,我没有太多时间 atm 来详细研究它。我真的很感激它,我稍后会回复它!
【解决方案4】:

Ok 最后,这是您需要的结果。 这个解决方案的好处是您不需要运行额外的脚本,也只需将组名作为参数传递,它只会返回您需要的列。享受。 :)

declare @aa varchar (200) = ''
declare @sql varchar(500) = ''
declare @groupinfo varchar(100) = 'GroupA'

Select @aa = coalesce (case when @aa = '' then Data else @aa + ',' + Data end ,'')
  from [AccessRights] where GroupA = 'y'

Set @sql = 'Select [Group],' +  @aa + ' from Data where [Group] = ' + '''' + @groupinfo + ''''
Exec(@sql)

+--------+--------+--------+
| Group  |  Data3 | Data4  |
+--------+--------+--------+
| GroupA |   9    |   4    | 
| GroupA |   1    |   5    |
+--------+--------+--------+

【讨论】:

  • 这个答案使用 T-SQL,它可以在 Microsoft SQL Server 中工作,但在 Access 中不起作用。
  • 很高兴知道在 SQL Server 上会有一个解决方案 :)
猜你喜欢
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多