2015-06-25 27 views
6

Tworzenie moich pierwszych zapytań SQL programu Microsoft Access. To nie powinno być takie trudne!
Mam 2 tabele:.Łączenie 2 zapytań - uzyskiwanie nazw kolumn w jednym i używanie wyników w innym zapytaniu

Data table AccessRights table

użytkownik należący do GroupA zalogowany chcę pokazać mu tylko te Data wiersze i kolumny tabeli, która GroupA jest przypisane, na przykład:

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

próbowałem to głupie opcję:

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

No, proszę powiedzieć nam, jakie kryteria odpowiedź musi się spotkać, aby zostać zaakceptowanym przez ciebie jako odpowiedź? Czy byłbyś do przyjęcia, gdybyś musiał uruchomić kod VBA, aby rozwiązać problem, czy też pracujesz tylko z projektantem zapytań? – Binarus

+0

Wolałbym robić to tylko w SQL. Ale wydaje się to niemożliwe bez zmiany struktury moich danych. Więc VBA też jest dobry. – ZygD

+0

Źródłem tego problemu jest schemat. Nie jestem pewien, jaki problem próbujesz rozwiązać, ale ten projekt tabeli/kolumny nie jest dobry. Właśnie dlatego masz problemy z SQL. Co się stanie, jeśli przypiszesz "y" do wszystkich wartości w kolumnach GroupA i GroupB tabeli AccessRights? Myślę, że to, co próbujesz zbudować, to oparty na rolach system uwierzytelniania. Twoje stoły będą się różnić. – itsben

Odpowiedz

3

używam tej kwerendy:

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

Do tego wyniku:

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

prostu ukryć wartości Data1 i Data2.


Jeśli naprawdę chcesz, aby ukryć kolumny musisz użyć VBA, że utworzyć funkcję VBA, które dadzą ostateczną ciąg kwerendy na podstawie swojej grupy:

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 

Dla przykładu; myQuery("GroupA") będzie

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

Dlaczego nie zamkniesz zestawu rekordów i nie ustawisz go na nic, gdy funkcja dobiegnie końca? Czy jest automatycznie zamknięty/ustawiony na nic? – ZygD

+0

@ZygD tak, jest to zmienna lokalna. i dobrze jest zamknąć to przed końcem. –

+0

Do tej pory lubię tę odpowiedź najbardziej, ponieważ nie wymaga zmiany mojej struktury danych. – ZygD

4

Prawdopodobnie byłoby lepiej po prostu przestawić tabelę danych i dodać kolumnę o danych. Zrób to samo dla praw dostępu.

Ty tabela danych będzie wyglądać mniej więcej tak:

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

AccessRights tak:

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

Następnie można po prostu połączyć dwie tabele razem i filtr, ile potrzeba.

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' 
+0

Dzięki za sugestię. Myślałem o obróceniu stołów i wciąż mam tę opcję w głowie. Jednak nadal chcę wierzyć, że powinien istnieć jakiś sposób osiągnięcia wyniku bez zmiany czegokolwiek. Nadal uważam, że każdy RDBMS jest elastyczny i nie chcę tego tak łatwo stracić ... :) – ZygD

+3

Ta odpowiedź pokazuje, że RDBMS * jest * elastyczny. Na swój sposób walczy się ze sposobem działania relacyjnych baz danych. Dostęp jest nieco bardziej wyrozumiały przy mieszaniu danych i prezentacji, ale ogólnie, aby użyć struktury tabeli, należy wybrać wiersze uporządkować dynamiczne kolumny w części prezentacji. Należy zauważyć, że wadą tego podejścia jest to, że wszystkie dane muszą mieć ten sam typ. – LoztInSpace

0

Ok Wreszcie tutaj jest wynik, który wymagane. Dobrą rzeczą w tym rozwiązaniu jest to, że nie trzeba uruchamiać dodatkowego skryptu, a także przekazać nazwę grupy jako parametr i zwróci ona tylko potrzebne kolumny. Cieszyć się. :)

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 | 
+--------+--------+--------+ 
+1

Ta odpowiedź używa T-SQL, który będzie działać w Microsoft SQL Server, ale nie będzie działał w programie Access. –

+0

Miło wiedzieć, że na serwerze SQL będzie rozwiązanie :) – ZygD

1

@ZygD, oto schemat:

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 

wytłumaczę. Najpierw definiujesz swoje "typy obiektów". Masz UŻYTKOWNIKA, GRUPĘ i to, co nazwałeś DANYMI. Poza tym dobrym pomysłem jest użycie innego słowa zamiast DATA. Użyj czegoś takiego jak ELEMENT, a nawet DATAITEM. W tym przykładzie użyję DATA. Ok, więc każda z tych tabel ma wartość całkowitą, ponieważ jest to klucz podstawowy. Klucz podstawowy jest unikalnym identyfikatorem rekordu w tabeli i zwiększa się automatycznie. Możesz to ustawić w Access.

Teraz, gdy masz już swoje trzy tabele typu obiektów, potrzebujesz czegoś, co nazywa się "tabelami złączeń", aby opisać relacje między tabelami "typu obiektu". Tabela USER_GROUP mówi, że użytkownik może należeć do jednej lub więcej grup. Na przykład, jeśli Użytkownik 1 należał zarówno do Grupy 1, jak i Grupy 2, w tabeli USER_GROUP byłyby dwa rekordy opisujące te relacje. Pierwszy wiersz będzie wynosił 1,1, a drugi - 1,2.

Tabela GROUP_DATA opisuje relacje między GRUPĄ a DANYMI. Na przykład grupa 1 może mieć dostęp do danych 2 i danych 3. Ponownie, w tabeli GROUP_DATA zostaną wyświetlone dwa wiersze opisujące te relacje. Pierwszy rząd wynosiłby 1,2, a drugi 1,3.

Teraz, ponieważ Użytkownik 1 należący do grupy 1, a potem Użytkownik 1 będzie miał dostęp do danych 2 i 3. Twój SQL następnie zostaje uproszczonej:

// 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 
+0

Dziękuję za odpowiedź. Szkoda, że ​​nie mam zbyt dużo czasu na zapoznanie się z nim w szczegółach. Naprawdę to doceniam i wrócę do tego nieco później! – ZygD