2015-06-25 10 views
6

Creazione delle prime query SQL di Microsoft Access. Non dovrebbe essere così difficile!
Ho 2 tabelle:.Combinazione di 2 query: acquisizione dei nomi delle colonne in una e utilizzo dei risultati in un'altra query

Data table AccessRights table

un utente appartenente al GroupA loggato voglio fargli vedere solo quelle Data righe e colonne che GroupA è assegnata a, come questo:

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

ho provato questo stupido opzione:

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

Ebbene, potrebbe dirci quali criteri una risposta deve incontrarsi per essere accettato come risposta da voi? Sarebbe accettabile per te se avessi bisogno di eseguire il codice VBA per risolvere il problema o stai lavorando solo con il progettista di query? – Binarus

+0

Preferirei farlo solo in SQL. Ma sembra impossibile senza modificare la struttura dei miei dati. Quindi anche VBA va bene. – ZygD

+0

La radice di questo problema è lo schema. Non sono sicuro di quale problema stai cercando di risolvere, ma questo progetto di tabella/colonna non è buono. Questo è il motivo per cui hai problemi con SQL. Che cosa succederà se si assegna "y" a tutti i valori nelle colonne GroupA e GroupB della tabella AccessRights? Penso che quello che stai cercando di costruire sia un sistema di autenticazione basato sui ruoli. I tuoi tavoli saranno diversi per quello. – itsben

risposta

3

Io uso questa domanda:

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

per questo risultato:

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

Ho appena nascondo valori di Data1 e Data2.


Se davvero si vuole nascondere le colonne è necessario utilizzare VBA che creo una funzione VBA che darà la stringa di query finale in base al gruppo:

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 

Per esempio; myQuery("GroupA") sarà

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

Perché non si chiude il recordset e non si imposta nulla quando la funzione arriva alla fine? È chiuso/impostato su nulla automaticamente? – ZygD

+0

@ZygD sì, è una variabile locale. ed è un buon punto chiuderlo prima della fine. –

+0

Finora questa risposta mi piace di più, perché non mi richiede di cambiare la struttura dei dati. – ZygD

4

Probabilmente sarebbe meglio ruotare la tabella dei dati e aggiungere una colonna denominata dati. Fai lo stesso per i diritti di accesso.

tabella di dati si dovrebbe guardare qualcosa di simile:

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

AccessRights come questo:

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

Poi si può solo unire le due tavoli insieme e filtro, se necessario.

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

Grazie per il suggerimento. Ho pensato di ruotare i tavoli e ho ancora questa opzione nella mia mente. Tuttavia, voglio ancora credere che ci dovrebbe essere un modo per ottenere il risultato senza cambiare nulla. Continuo a pensare che qualsiasi RDBMS sia flessibile e non voglio perdere questa convinzione così facilmente ... :) – ZygD

+3

Questa risposta mostra come RDBMS * è * flessibile. La tua strada è combattere contro il modo in cui funzionano i database relazionali. L'accesso è un po 'più clemente nel mixare i dati e la presentazione, ma generalmente per usare la struttura della tabella si selezionano le righe per ordinare le colonne dinamiche nella parte della presentazione. Si noti che uno svantaggio di questo approccio è che tutti i dati devono avere lo stesso tipo. – LoztInSpace

0

Ok Finalmente ecco il risultato richiesto. La cosa buona con questa soluzione è che non è necessario eseguire script aggiuntivi e anche solo passare il nome del gruppo come parametro e restituirà solo le colonne necessarie. Godere. :)

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

Questa risposta utilizza T-SQL che funzionerà in Microsoft SQL Server ma non funzionerà in Access. –

+0

Bello sapere che su SQL Server ci sarebbe una soluzione :) – ZygD

1

@ZygD, Ecco lo schema:

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 

ti spiego. Per prima cosa definisci i tuoi "tipi di oggetto". Hai un UTENTE, un GRUPPO e ciò che hai chiamato DATI. A parte questo è probabilmente una buona idea usare un'altra parola invece di DATA. Usa qualcosa come ITEM, o anche DATAITEM. Per questo esempio userò i DATI. Ok, quindi ognuna di queste tabelle ha un valore intero come chiave primaria. La chiave primaria è l'identificativo univoco per il record nella tabella e aumenta automaticamente. Puoi impostarlo in Access.

Ora che si dispone delle tre tabelle di tipi di oggetto, è necessario ciò che viene chiamato "join tables" per descrivere le relazioni tra le tabelle di "tipo oggetto". La tabella USER_GROUP dice che un utente può appartenere a uno o più gruppi. Ad esempio, se l'Utente 1 apparteneva sia al Gruppo 1 sia al Gruppo 2, nella tabella USER_GROUP si avrebbero due record per descrivere tali relazioni. La prima riga sarebbe 1,1 e la seconda riga sarebbe 1,2.

La tabella GROUP_DATA descrive la relazione tra GROUP e DATA. Ad esempio, il Gruppo 1 potrebbe avere accesso a Dati 2 e Dati 3. Di nuovo, si avranno due righe nella tabella GROUP_DATA per descrivere tali relazioni. La prima riga sarebbe 1,2 e la seconda sarebbe 1,3.

Ora, a causa Utente 1 appartiene al gruppo 1, quindi l'utente 1 avrà accesso ai dati 2 e 3. Il vostro SQL diventa quindi semplificato:

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

Grazie per la risposta. Peccato che non abbia molto tempo per studiarlo nei dettagli. Lo apprezzo davvero e tornerò un po 'più tardi! – ZygD

Problemi correlati