For example, The table has 3 rows and 3 columns:
Peter 25 M
John 29 M
Alex 25 M
And I want to query the table and get
Peter 25 M
John 29
Alex
The method I have tried:
SELECT DISTINCT Name,Age,Gender FROM table
The output is still
Peter 25 M
John 29 M
Alex 25 M
How to achieve the table that there is no redundant entries for every field? Thanks.
Thanks for the help from all of you, especially the help from donPablo. Here's my VBA code to achieve that. Since I am totally new to VBA, the code might not be very clean and efficient. But at least it works.
Option Compare Database
Sub ReadDistinctValue()
Dim d As Database
Dim rs As Recordset
Dim FN As Field, Age As Field, Sex As Field
Set d = CurrentDb()
Set rs = d.OpenRecordset("Table1")
Set FN = rs.Fields("FN")
Set Age = rs.Fields("Age")
Set Sex = rs.Fields("Sex")
d.Execute "CREATE TABLE Table4 (FN Text,Age Text,Sex Text)"
While Not rs.EOF
If CheckFN(FN) = False Then
Call WriteFN(FN)
End If
If CheckAge(Age) = False Then
Call WriteAge(Age)
End If
If CheckSex(Sex) = False Then
Call WriteSex(Sex)
End If
rs.MoveNext
Wend
rs.Close
End Sub
Function CheckFN(FN As Field) As Boolean
Dim d As Database
Dim rs_new As Recordset
Dim FN_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set FN_new = rs_new.Fields("FN")
CheckFN = False
Do While Not rs_new.EOF
If FN_new = FN Then
CheckFN = True
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
Function WriteFN(FN As Field)
Dim d As Database
Dim rs_new As Recordset
Dim FN_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set FN_new = rs_new.Fields("FN")
If Not rs_new.EOF Then
rs_new.MoveFirst
End If
Do While True
If rs_new.EOF Then
rs_new.AddNew
FN_new = FN
rs_new.Update
Exit Do
End If
If IsNull(FN_new.Value) Then
rs_new.Edit
FN_new = FN
rs_new.Update
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
Function CheckAge(Age As Field) As Boolean
Dim d As Database
Dim rs_new As Recordset
Dim Age_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set Age_new = rs_new.Fields("Age")
CheckAge = False
Do While Not rs_new.EOF
If Age_new = Age Then
CheckAge = True
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
Function WriteAge(Age As Field)
Dim d As Database
Dim rs_new As Recordset
Dim Age_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set Age_new = rs_new.Fields("Age")
If Not rs_new.EOF Then
rs_new.MoveFirst
End If
Do While True
If rs_new.EOF Then
rs_new.AddNew
Age_new = Age
rs_new.Update
Exit Do
End If
If IsNull(Age_new.Value) Then
rs_new.Edit
Age_new = Age
rs_new.Update
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
Function CheckSex(Sex As Field) As Boolean
Dim d As Database
Dim rs_new As Recordset
Dim Sex_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set Sex_new = rs_new.Fields("Sex")
CheckSex = False
Do While Not rs_new.EOF
If Sex_new = Sex Then
CheckSex = True
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
Function WriteSex(Sex As Field)
Dim d As Database
Dim rs_new As Recordset
Dim Sex_new As Field
Set d = CurrentDb()
Set rs_new = d.OpenRecordset("Table4")
Set Sex_new = rs_new.Fields("Sex")
If Not rs_new.EOF Then
rs_new.MoveFirst
End If
Do While True
If rs_new.EOF Then
rs_new.AddNew
Sex_new = Sex
rs_new.Update
Exit Do
End If
If IsNull(Sex_new.Value) Then
rs_new.Edit
Sex_new = Sex
rs_new.Update
Exit Do
End If
rs_new.MoveNext
Loop
rs_new.Close
End Function
By naming the three columns, you are retrieving distinct combinations of that set of values.
If you want lists of distinct values, name each individually in a select.
SELECT DISTINCT Name FROM table
SELECT DISTINCT Age FROM table
SELECT DISTINCT Gender FROM table
If you are trying to get them to display as you have in your example, that will have to be accomplished by some GUI functionality. SQL database engines are not good at display trickery, just handling data.
I have expanded the table values a little, just to see what would happen --
FN Age Sex
Alice 28 F
Ben 19 M
Charles 33 M
Doug 23 M
Elaine 21 F
Frank 25 M
Gwen 28 F
Helen 33 F
Alice 17 F
Ben 21 F
Then I developed a single query for FN, and later generalized to all three fields --
The clue is to sequence # each FN/AGE/SEX and then join on that seq#--
SELECT
AB.fn,
CD.age,
EF.sex
FROM
((SELECT A.fn, Count(B.fn) AS CNTfn
FROM
(SELECT DISTINCT fn FROM table1) AS A,
(SELECT DISTINCT fn FROM table1) AS B
WHERE B.fn <= A.fn
GROUP BY A.fn) AS AB
LEFT JOIN
(SELECT C.age, Count(D.age) AS CNTage
FROM
(SELECT DISTINCT age FROM table1) AS C,
(SELECT DISTINCT age FROM table1) AS D
WHERE D.age <= C.age
GROUP BY C.age) AS CD
ON AB.cntfn = CD.cntage)
LEFT JOIN
(SELECT E.sex, Count(F.sex) AS CNTsex
FROM
(SELECT DISTINCT sex FROM table1) AS E,
(SELECT DISTINCT sex FROM table1) AS F
WHERE F.sex <= E.sex
GROUP BY E.sex) AS EF
ON AB.cntfn = EF.CNTsex;
This gives the results desired --
FN AGE SEX
Alice 17 F
Ben 19 M
Charles 21
Doug 23
Elaine 25
Frank 28
Gwen 33
Helen
I changed the Sex in my sample table, and added to the following as the first sequencing of the un-Distinct whole table and changed the ON... to XZ.cntall ...
(SELECT X.FN & X.AGE & X.SEX, Count(*) AS CNTall
FROM
(SELECT DISTINCT FN, AGE, SEX FROM table1) AS X,
(SELECT DISTINCT FN, AGE, SEX FROM table1) AS Z
WHERE Z.FN & Z.AGE & Z.SEX <= X.FN & X.AGE & X.SEX
GROUP BY X.FN, X.AGE, X.SEX) as XZ
and now get these results
fn age sex
Alice 17 M
Ben 19 N
Charles 21 O
Doug 23 P
Elaine 25 Q
Frank 28 R
Gwen 33 W
Helen X
Y
Z
There is probably an SQL solution for this. I am constantly amazed at what can be done. However, my answer is that this is a perfect application for VBA.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.