Reputation: 47
I have the following table:
Table1
Color Room type
Black Large
White Large
White Small
Black Medium
Black Small
I want to run a query that:
Notice that my query is more complicated than that and it has other columns and many tables, but I just want to add the column that specifies if large rooms are mostly white or black.
Upvotes: 3
Views: 16095
Reputation: 11
You can try the following implementation:
SELECT Table1.[Room Type],
Count(IIf(Table1.Color="White",1,Null)) AS CountWhite,
Count(IIf(Table1.Color="Black",1,Null)) AS CountBlack,
IIf(CountWhite>CountBlack,"White",(IIf(CountBlack>CountWhite,"Black","Tie"))) AS Expr1
FROM Table1
GROUP BY Table1.[Room Type];
Upvotes: 1
Reputation: 11
I think something like the following would accomplish what you described:
SELECT RoomType,
IIF(BlackCount>WhiteCount, "Black", IIF(BlackCount<WhiteCount, "White", "Unidentified")) AS PrevailingColor
FROM
(SELECT RoomType, SUM(IIF(Color="Black",1,0)) AS BlackCount, SUM(IIF(Color="White",1,0)) AS WhiteCount
FROM Table1
GROUP BY RoomType)
;
Upvotes: 1
Reputation: 115520
For all types of rooms:
SELECT RoomType
, Count( IIF(Color="White",1,NULL) ) AS CountWhite
, Count( IIF(Color="Black",1,NULL) ) AS CountBlack
, IIF( Count( IIF(Color="White",1,NULL) )
> Count( IIF(Color="Black",1,NULL) )
, "White"
, IIF( Count( IIF(Color="White",1,NULL) )
= Count( IIF(Color="Black",1,NULL) )
, NULL
, "Black"
)
)
AS Result
FROM Rooms
GROUP BY RoomType
For "Large" rooms only:
SELECT IIF( Count( IIF(Color="White",1,NULL) )
> Count( IIF(Color="Black",1,NULL) )
, "White"
, IIF( Count( IIF(Color="White",1,NULL) )
= Count( IIF(Color="Black",1,NULL) )
, NULL
, "Black"
)
)
AS Result
FROM Rooms
WHERE RoomType = "Large"
Upvotes: 4
Reputation: 603
Start with the following query in MS Access. In my example, I've saved it with the name qryRoomColorCounts:
SELECT
tblRooms.RoomType, tblRooms.Color, Count(*) AS ColorCount
FROM tblRooms
GROUP BY tblRooms.RoomType, tblRooms.Color
You can then use this SQL to get your result:
SELECT
tblRooms.RoomType,
(SELECT TOP 1 qryRoomColorCounts.Color FROM qryRoomColorCounts WHERE
qryRoomColorCounts.RoomType=tblRooms.RoomType
ORDER BY qryRoomColorCounts.ColorCount DESC) AS MostUsedColor
FROM tblRooms
GROUP BY tblRooms.RoomType
I can't get your suggestion to work, can you debug please: no references are required (uses late binding), just paste into any VBA standard code module (e.g. use Excel) and run:
Sub NotSoBlackAndWhite()
On Error Resume Next
Kill Environ$("temp") & "\DropMe2.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe2.mdb"
With .ActiveConnection
Dim Sql As String
Sql = _
"CREATE TABLE tblRooms" & vbCr & "(" & vbCr & " Color VARCHAR(100)" & _
" NOT NULL, " & vbCr & " RoomType NVARCHAR(100) NOT" & _
" NULL, " & vbCr & " UNIQUE (Color, RoomType)" & vbCr & ");"
.Execute Sql
Sql = _
"CREATE VIEW qryRoomColorCounts AS " & vbCr & "SELECT" & _
" " & vbCr & "tblRooms.RoomType, tblRooms.Color, Count(*)" & _
" AS ColorCount " & vbCr & "FROM tblRooms " & vbCr & "GROUP BY" & _
" tblRooms.RoomType, tblRooms.Color"
.Execute Sql
Sql = _
"INSERT INTO tblRooms (Color, RoomType) VALUES" & _
" ('Black', 'Large');"
.Execute Sql
Sql = _
"INSERT INTO tblRooms (Color, RoomType) VALUES" & _
" ('White', 'Large');"
.Execute Sql
Sql = _
"INSERT INTO tblRooms (Color, RoomType) VALUES" & _
" ('White', 'Small');"
.Execute Sql
Sql = _
"INSERT INTO tblRooms (Color, RoomType) VALUES" & _
" ('White', 'Med');"
.Execute Sql
Sql = _
"INSERT INTO tblRooms (Color, RoomType) VALUES" & _
" ('Black', 'Small');"
.Execute Sql
Sql = _
"SELECT " & vbCr & "tblRooms.RoomType, " & vbCr & "(SELECT TOP" & _
" 1 qryRoomColorCounts.Color FROM qryRoomColorCounts" & _
" WHERE" & vbCr & " qryRoomColorCounts.RoomType=tblRooms.RoomType" & _
" " & vbCr & " ORDER BY qryRoomColorCounts.ColorCount" & _
" DESC) AS MostUsedColor " & vbCr & "FROM tblRooms " & vbCr & "GROUP" & _
" BY tblRooms.RoomType"
Dim rs
Set rs = .Execute(Sql) ' <--- ERROR HERE '
MsgBox rs.GetString
End With
Set .ActiveConnection = Nothing
End With
End Sub
Upvotes: -1
Reputation: 57023
As this is Access (ACE, Jet, whatever), we probably need to use intermediary result sets via VIEW
s (saved query objects, querydefs, whatever):
CREATE VIEW Table1ColorTallies
(
Color, tally
)
AS
SELECT Color, COUNT(*) AS tally
FROM Table1
GROUP
BY Color;
CREATE VIEW Table1ColorsWithMaxTallies
(
Color
)
AS
SELECT T1.Color
FROM Table1ColorTallies AS T1
WHERE T1.tally = (
SELECT MAX(T2.tally)
FROM Table1ColorTallies AS T2
);
Using the VIEW
s to get the desired result:
SELECT Color
FROM Table1ColorsWithMaxTallies
WHERE 1 = (
SELECT COUNT(*)
FROM Table1ColorsWithMaxTallies AS T2
);
Note the above CREATE VIEW
SQL DDL must be executed individually in ANSI-92 Query Mode. Alternatively, create them as saved query objects (querydefs, whatever) using the Access UI (DAO, whatever) in the usual way.
Here's some VBA to create a new db called DropMe.mdb in your temp folder, create Table1
with sample data, then create my suggested VIEW
s and show the result of my suggested query in a message box. Uses ADO but no references are required (uses late binding). Just paste in any VBA standard code module (e.g. use Excel) and run. I think it will scale well to more than 1 color ;)
Sub BlackAndWhite()
On Error Resume Next
Kill Environ$("temp") & "\DropMe.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
With .ActiveConnection
Dim Sql As String
Sql = _
"CREATE TABLE Table1" & vbCr & "(" & vbCr & " Color VARCHAR(100)" & _
" NOT NULL, " & vbCr & " Room_type NVARCHAR(100) NOT" & _
" NULL, " & vbCr & " UNIQUE (Color, Room_type)" & vbCr & ");"
.Execute Sql
Sql = _
"CREATE VIEW Table1ColorTallies" & vbCr & "(" & vbCr & " Color," & _
" tally" & vbCr & ")" & vbCr & "AS " & vbCr & "SELECT Color, COUNT(*) AS tally" & vbCr & "" & _
" FROM Table1" & vbCr & " GROUP " & vbCr & " BY Color;"
.Execute Sql
Sql = _
"CREATE VIEW Table1ColorsWithMaxTallies" & vbCr & "(" & vbCr & "" & _
" Color" & vbCr & ")" & vbCr & "AS " & vbCr & "SELECT T1.Color" & vbCr & " FROM Table1ColorTallies" & _
" AS T1" & vbCr & " WHERE T1.tally = (" & vbCr & " " & _
" SELECT MAX(T2.tally)" & vbCr & " " & _
" FROM Table1ColorTallies AS T2" & vbCr & "" & _
" );"
.Execute Sql
Sql = _
"INSERT INTO Table1 (Color, Room_type) VALUES" & _
" ('Black', 'Large');"
.Execute Sql
Sql = _
"INSERT INTO Table1 (Color, Room_type) VALUES" & _
" ('White', 'Large');"
.Execute Sql
Sql = _
"INSERT INTO Table1 (Color, Room_type) VALUES" & _
" ('White', 'Small');"
.Execute Sql
Sql = _
"INSERT INTO Table1 (Color, Room_type) VALUES" & _
" ('White', 'Med');"
.Execute Sql
Sql = _
"INSERT INTO Table1 (Color, Room_type) VALUES" & _
" ('Black', 'Small');"
.Execute Sql
Sql = _
"SELECT Color" & vbCr & " FROM Table1ColorsWithMaxTallies" & vbCr & "" & _
" WHERE 1 = (" & vbCr & " SELECT COUNT(*)" & vbCr & "" & _
" FROM Table1ColorsWithMaxTallies" & _
" AS T2" & vbCr & " );"
Dim rs
Set rs = .Execute(Sql)
MsgBox rs.GetString
End With
Set .ActiveConnection = Nothing
End With
End Sub
Upvotes: 1
Reputation: 753585
Since your question is not yet clear, we have to make some fairly sweeping guesses about what you are after. If your table is really more like:
Rooms
RoomID Color Room type
1 Black Large
2 White Large
3 White Small
4 Black Medium
5 Black Small
6 Black Large
7 White Large
8 White Small
9 White Large
10 White Large
And if you want to know whether there are more black or white rooms of each of the three sizes, and you specify something for 'there are an equal number of black and white rooms' (grey?), and if MS Access can use this syntax, then maybe:
Number of rooms of each colour at each size:
SELECT [Room type] AS RoomType, Color, COUNT(*) AS RoomCount
FROM Rooms
GROUP BY RoomType, Color
Self-join this result to get black and white counts into single table:
SELECT NVL(Black.RoomType, White.RoomType) AS RoomType,
NVL(WhiteCount, 0) AS WhiteCount,
NVL(BlackCount, 0) AS BlackCount
FROM (SELECT [Room type] AS RoomType, COUNT(*) AS WhiteCount
FROM Rooms
WHERE Color = 'White'
GROUP BY RoomType
) AS White
FULL OUTER JOIN
(SELECT [Room type] AS RoomType, COUNT(*) AS BlackCount
FROM Rooms
WHERE Color = 'Black'
GROUP BY RoomType
) AS Black
ON Black.RoomType = White.RoomType
(I don't know if MS Access supports FULL OUTER JOIN. If not, you have to work harder. Similarly, I've not checked whether it supports NVL - maybe it supports COALESCE instead.)
This will give you a series of rows, one for each room type, with a WhiteCount and a BlackCount.
Now you just need to post-process that to give you the information you are after - if my guesswork is justified.
Edit: Must use NVL() or equivalent on RoomType and include table aliases; now tested and producing the correct answer on MacOS X 10.6.7 with IBM Informix Dynamic Server 11.70.FC1:
Roomtype Whitecount Blackcount
Large 4 2
Small 2 1
Medium 0 1
If MS Access does not support FULL OUTER JOIN, then the query is very much messier. Does it support LEFT and RIGHT (OUTER) JOIN? Let's hope so because then you can use this (which has been changed to assume that the column name is Rooms.RoomType (no space in the name):
SELECT NVL(White.RoomType, Black.RoomType) AS RoomType,
NVL(WhiteCount, 0) AS WhiteCount,
NVL(BlackCount, 0) AS BlackCount
FROM (SELECT RoomType AS RoomType, COUNT(*) AS WhiteCount
FROM Rooms
WHERE Color = 'White'
GROUP BY RoomType
) AS White
LEFT OUTER JOIN
(SELECT RoomType AS RoomType, COUNT(*) AS BlackCount
FROM Rooms
WHERE Color = 'Black'
GROUP BY RoomType
) AS Black
ON Black.RoomType = White.RoomType
UNION
SELECT NVL(White.RoomType, Black.RoomType) AS RoomType,
NVL(WhiteCount, 0) AS WhiteCount,
NVL(BlackCount, 0) AS BlackCount
FROM (SELECT RoomType AS RoomType, COUNT(*) AS WhiteCount
FROM Rooms
WHERE Color = 'White'
GROUP BY RoomType
) AS White
RIGHT OUTER JOIN
(SELECT RoomType AS RoomType, COUNT(*) AS BlackCount
FROM Rooms
WHERE Color = 'Black'
GROUP BY RoomType
) AS Black
ON Black.RoomType = White.RoomType;
This formulation relies on UNION removing duplicate rows. Given the test data, it produces the same result. You could compact it a little by using White.RoomType in the main select-list of the first half of the UNION (instead of the NVL expression) and Black.RoomType in the second half.
If MS Access doesn't support any outer joins, then (a) it's time to upgrade to a real DBMS and (b) let me know and we'll work out the long-handed 3-way UNION way of doing the same job.
Upvotes: 0