I asked this question a few months back but now I'm working out of MS-Access and I'm unsure how to proceed. I have a query that lists the bldid, unitid, and resident id in separate columns. I'd like to modify the query output in Microsoft Access so that each resident that shares a building / unit shows as a new column on the same row as shown below. But since I'm limited to MS Access I can't seem to use with, cte, or rownumber. I'm at a loss as to how to do this so any help would be appreciated.
Query1
BldID
UnitID
ResidentID
1
201
John Smith
1
201
Jane Doe
1
202
Daniel Jones
1
202
Mark Garcia
2
201
Maria Lee
2
201
Paul Williams
2
201
Mike Jones
Desired Output from edited Query
BldID
UnitID
Res1
Res2
Res3
1
201
John Smith
Jane Doe
1
202
Daniel Jones
Mark Garcia
2
201
Maria Lee
Paul Williams
Mike Jones
You can use a Crosstab Query
TRANSFORM Max(Resident.ResidentID) AS MaxOfResidentID
SELECT Resident.BldID, Resident.UnitID
FROM Resident
GROUP BY Resident.BldID, Resident.UnitID
ORDER BY Resident.BldID, Resident.UnitID
PIVOT "Res" & (DCount("*",
"Resident",
"BldID=" & [BldID] & " AND UnitID=" & [UnitID] &
" AND ResidentID<'" & [ResidentID] & "'") + 1);
If you need a constant number of columns (e.g. if you want to create an Access report), then you can add an In clause to this query (before the ;):
In ("Res1","Res2","Res3","Res4","Res5","Res6")
This always creates 6 columns with the same names.
The difficulty is to get the row number per BldID/UnitID group. This is achieved by
DCount(1,
"Resident",
"BldID=" & [BldID] &
" AND UnitID=" & [UnitID] &
" AND ResidentID<'" & [ResidentID] & "'") + 1
where Resident is the name of your table or query. It counts residents having the same BldID and UnitID but having a smaller ResidentID. Adding 1 to this count yields the row number starting at 1. Then the string "Res" is prepended to build the column name.
Note that the residents are listed in alphabetical order form left to right.
Related
I have two tables in MS Access, one with foods and associated companies:
FoodID
Food
Company
1
Apple
Vino Farms
2
Orange
Citrus Co.
3
Banana
Vino Farms
and one with information about whether someone ate the food
ClientID
ClientName
Apple
Orange
Banana
1
Bob
Yes
No
Yes
2
Tyler
Yes
Yes
Yes
3
Joe
No
No
No
I'd like to write a query that creates a column populated by the company that makes the foods someone reported eating, separated by commas. If someone reports eating a more than one food made by the same company, I only want the company's name listed once:
ClientID
ClientName
AssociatedCompanies
1
Bob
Vino Farms
2
Tyler
Vino Farms, Citrus Co.
3
Joe
Any help would be greatly appreciated!
As indicated by Gustav, start by normalizing your "ate food" Table. It should look like:
1 Bob Apple
1 Bob Banana
2 Tyler Apple
2 Tyler Orange
2 Tyler Banana
You then get what you want with the following Query:
-- Group companies into one field, sepparated with commas
SELECT ClientID, ClientName, RemoveCommas(Company1 & ", " & Company2 & ", " ... & CompanyN)
FROM
( -- Convert rows (records) into columns (fields)
SELECT ClientID, ClientName
, Max(Iif(Company="Vino Farms", "Vino Farms", Null)) AS Company1
, Max(Iif(Company="Citrus Co.", "Citrus Co.", Null)) AS Company2
, ...
, Max(Iif(Company="Last_company", "Last_company", Null)) AS CompanyN
FROM
(-- Replace food by its manufacturing company
SELECT DISTINCT ClientID, ClientName, Company
FROM
Table_ate_food_normalized AS Ate
INNER JOIN
Table_food AS Comp
ON Ate.Food = Comp.Food
)
GROUP BY ClientID, ClientName
)
Notice the following relevant points:
This will only work, as you notice, for a fixed number of companies with names hardcoded in the Query. This is a very severe limitation. If these restrictions are not satisfied, I suggest that you use a TRANSFORM Query, but, you would not get the companies as a single text field with values sepparated by commas, and you would rather get them as a variable number of fields, each field having a Yes/No value (similar to your current "ate food" table).
I am assuming that the values of "food" and "Company" are each a candidate key in its Table. Otherwise, use the corresponding ID fields, and get the actual values using an inner join.
If you want to understand better the part of converting rows into columns, you may check the Query "K_rows_into_columns_1" from the database of examples dowloadable from LightningGuide.net.
You have to code the user defined VBA function "RemoveCommas()" to remove unncessary commas from the string containing the listing of companies. If unncessesary commas do not bother you, then you can do the Query without coding this functions.
If you want to code the TRANSFORM alternative that I suggested above, you may check the Query "K_rows_into_columns_2" from the database of examples dowloadable from LightningGuide.net.
I have a list of data that happens to have been set up like this:
entryID fieldID Value
100 1 John
100 2 Smith
100 3 USA
101 1 Jane
101 2 Doe
101 3 USA
The way it works is, when a "ticket" is created, it assigns an entryID for all the data in that ticket, but each field also has it's own fieldID. So first name is always a fieldID of 1, last name is 2, etc.
What I need to be able to do is create a view that will look like this:
First Name Last Name Country
John Smith USA
Jane Doe USA
I need to be able to do this in MySQL, and not SQL or excel, as some other similar problems have addressed.
I just found the answer to my own question, so I will post it here for future users.
This website explains how to do exactly what I was asking for: http://stratosprovatopoulos.com/web-development/mysql/pivot-a-table-in-mysql/
I tried to create a VIEW that merge some tables in order to have the "hottest" teacher in a educational platform.
First, I have a table with the users (some teachers, some students),
then in other I have the lessons created by the teachers,
finally, other one that has the relation between students and lesson.
when I use this SQL sentence
CREATE OR REPLACE VIEW `skn_teachers` AS
select
`u`.`id_skn_users` AS `id_skn_users`,
`u`.`firstName` AS `firstName`,
`u`.`lastName` AS `lastName`,
COUNT(`ls`.`createdBy`) AS `countLessons`
from (`skn_users` AS `u`, `skn_rolesxusers` AS `rxu`, `skn_roles` AS `ro`, `skn_approved_lessons` AS `ls`)
where ((`rxu`.`id_skn_users` = `u`.`id_skn_users`) and (`rxu`.`id_skn_roles` = `ro`.`id_skn_roles`) and (`ro`.`name` = 'teacher') and (`ls`.`createdBy` = `rxu`.`id_skn_users`))
group by `u`.`id_skn_users`
the row countLessons show me the number of lessons per teacher eg.
id | firstName | lastName | countLessons
1 Pepito Perez 1
2 Julián Figueroa 7
3 Daniel Aguirre 2
which is correctly the number of lessons per teacher.
but I need the number of students that have the lessons created by each teacher (all of them, sum of all students in all lessons of THAT teacher), countStudentsByTeacher, in one of my attempts, get this SQl and it was a surprise when I got the number of students by teacher but I don't understand clearly what I did.
new SQL sentence:
CREATE OR REPLACE VIEW `skn_teachers` AS
select
`u`.`id_skn_users` AS `id_skn_users`,
`u`.`firstName` AS `firstName`,
`u`.`lastName` AS `lastName`,
COUNT(`ls`.`createdBy`) AS `countStudents`
from (`skn_users` AS `u`, `skn_rolesxusers` AS `rxu`, `skn_roles` AS `ro`, `skn_approved_lessons` AS `ls`, `skn_lessonsxusers` AS `lxu`)
where ((`rxu`.`id_skn_users` = `u`.`id_skn_users`) and (`rxu`.`id_skn_roles` = `ro`.`id_skn_roles`) and (`ro`.`name` = 'teacher') and (`ls`.`createdBy` = `rxu`.`id_skn_users`) and (`ls`.`id_skn_lessons` = `lxu`.`id_skn_lessons`))
group by `u`.`id_skn_users`
//
id | firstName | lastName | countLessons
1 Pepito Perez 10
2 Julián Figueroa 15
3 Daniel Aguirre 8
here, column countLessons shows really the number of students into all lessons created by each teacher, exactly what I wanted but I want to know why this works.
Thanks in advance!
In your 2nd query, you added at join to the table skn_lessonsxusers. This causes the 2nd query to return additional rows per each student that was assigned the lesson. The first query only returned the lessons that were created by each teacher.
Example:
Looking at the teacher "Daniel Aguirre", the underlying non-aggregated data for the first query might look like this:
id | firstName | lastName | Lesson
3 Daniel Aguirre Math 101
3 Daniel Aguirre CS 104
So there are 2 lessons that he teaches.
Now if you add in the students for each lesson, i.e. the 2nd query, then the data might look like this.
id | firstName | lastName | Lesson | Student
3 Daniel Aguirre Math 101 John
3 Daniel Aguirre Math 101 Bob
3 Daniel Aguirre Math 101 Sara
3 Daniel Aguirre Math 101 Mary
3 Daniel Aguirre CS 104 John
3 Daniel Aguirre CS 104 Bob
3 Daniel Aguirre CS 104 Dan
3 Daniel Aguirre CS 104 Sally
So now when you aggregate this 2nd set of data, it will show a count of 8 because there are 8 student/lesson combination for Daniel Aguirre.
Now assuming that John and Bob in the above 2nd data set are the same student, there are not really 8 different students taking lessons from Daniel Aguirre, there are 6 (John, Bob, Sara, Mary, Dan, and Sally). If you wanted to show 6 in this example you would use:
COUNT(DISTINCT `lxu`.`student_id`) AS `countStudents`
where student_id is the column that represents a unique student in the skn_lessonsxusers table. NOTE: your column is probably a different name than "student_id", but I don't know your table structure for this example so I just used "student_id".
It works because you multiply each lesson by each student in this lesson
join... 'skn_approved_lessons' AS 'ls'
where... and ('ls'.'createdBy' = 'rxu'.'id_skn_users')
I need pointed to the correct direction. I need to create a fixed width file from Access. The data will be coming from 2 tables (employer and employee). The text file must display the employer record, then the next records will contain employee data. The resulting file layout with then be used to upload into a separate system.
For example:
Employer Table
RecordID - 2 char - always 01
EmployerNumber - 6 char
EmployerName - 25 char
ReportID (pk) - Not included on text file, only used to relate employer with employee
Employee Table
RecordID - 2 char - always 02
EmployeeNumber - 4 char
EmployeeName - 25 char
ReportID (fk) - Not included on text file, only used to relate employee with employer
Resulting text file:
01012345PENGUINS
028686CROSBY
027777MALKIN
026666LEMIEUX
01012345ACME INC
021122BUGS BUNNY
021133DAFFY DUCK
029872ROAD RUNNER
Assuming that [ReportID] is integer, so the sample data looks like this for [Employer] ...
ReportID EmployerNumber EmployerName RecordID
-------- -------------- ------------ --------
1 012345 PENGUINS 01
2 012345 ACME INC 01
... and this for [Employee] ...
ReportID EmployeeNumber EmployeeName RecordID
-------- -------------- ------------ --------
1 8686 CROSBY 02
1 7777 MALKIN 02
1 6666 LEMIEUX 02
2 1122 BUGS BUNNY 02
2 1133 DAFFY DUCK 02
2 9872 ROAD RUNNER 02
the query
SELECT
RecordID & EmployerNumber & EmployerName AS RowData,
CDbl(ReportID) AS RowSort
FROM Employer
UNION ALL
SELECT
RecordID & EmployeeNumber & EmployeeName AS RowData,
CDbl(ReportID) + Val(EmployeeNumber) / 10000 AS RowSort
FROM Employee
returns
RowData RowSort
----------------- -------
01012345PENGUINS 1
01012345ACME INC 2
028686CROSBY 1.8686
027777MALKIN 1.7777
026666LEMIEUX 1.6666
021122BUGS BUNNY 2.1122
021133DAFFY DUCK 2.1133
029872ROAD RUNNER 2.9872
so the query
SELECT RowData
FROM
(
SELECT
RecordID & EmployerNumber & EmployerName AS RowData,
CDbl(ReportID) AS RowSort
FROM Employer
UNION ALL
SELECT
RecordID & EmployeeNumber & EmployeeName AS RowData,
CDbl(ReportID) + Val(EmployeeNumber) / 10000 AS RowSort
FROM Employee
)
ORDER BY RowSort
returns
RowData
-----------------
01012345PENGUINS
026666LEMIEUX
027777MALKIN
028686CROSBY
01012345ACME INC
021122BUGS BUNNY
021133DAFFY DUCK
029872ROAD RUNNER
Just save that last query in Access and then export it as text.
Your problem is a little complicated for a beginner but it has 2 parts:
You need to join the 2 tables. You should google for 'SQL Inner Joins' for a few examples.
You need to export the data in the format you want. You can do this with using the Left() function.
Assuming your tables are called Employee and Employer, consider this SQL statement:
Select
ER.RecordID &
left(ER.EmployerNumber & " ",6) &
left(ER.EmployerName & " ",25) &
EE.RecordID &
Left(EE.EmployeeNumber & " ",4) &
Left(EE.EmployeeName & " ",25) as SingleCol
From Employee EE
Join Employer ER on EE.ReportID=ER.ReportID
This query joins the 2 tables (see the Join at the bottom) and displays first the 3 fields from your Employer table followed by the 3 fields from the Employee table. The Left() statement with all the spaces pads the field with spaces. This query will return exactly 1 long text field.
I have an Access data table with 10 columns with basis of complain(bullying, harassment, etc.) that are yes or no type. In a report I want all the columns that were clicked as yes. Obviously I do not want all the columns to be on the report and a check mark if it applies to the record. I want to create another column name called basis and in this the column names of all basis columns that are clicked as yes separated by a comma Eg: Sexual Harassment, Race Discrimination,...
Any idea how I should proceed to get this result?
If you have a table named [Complaints]...
Accused Bullying Harassment
------------- -------- ----------
Doe, John True False
Smith, Jane False True
Muntz, Nelson True True
...then you can use the following query to list their alleged transgressions:
SELECT
Accused,
Trim(
IIf(Bullying, "Bullying", "")
& " " & IIf(Harassment, "Harassment", "")
) AS ComplaintList
FROM Complaints
...returning
Accused ComplaintList
------------- -------------------
Doe, John Bullying
Smith, Jane Harassment
Muntz, Nelson Bullying Harassment