using MS Access 2010, editing a form, 3 tables, one table is "one to many" and want to have query across one row - sql

Example:
(using a comma, to show columns & "A_", "B_", "C_" to show tables)
I currently have...
A_John, A_Doe, B_MemStartDate, C_Date,
A_John, A_Doe, B_MemStartDate, C_Date,
A_John, A_Doe, B_MemStartDate, C_Date,
I would like Table "C" columns to be pulled by Course but shown as the "Date" column... in other words, example, where Course = 1, use Date... etc...
The table would have each member's course history.
MemberID, CourseID, Date
JohnDoe, Course1, 10-10-13
JohnDoe, Course2, 10-11-13
JohnDoe, Course3, 10-12-13
The table C is the one to many of course, with the goal to show the date that the course was taken as I would title the columns with the 3 different courses I want to show... (I want to pull only 3 different courses)
I would like to have them in a row...
A_John, A_Doe, B_Start Date, C_Course1Date, C_Course2Date, C_Course3Date
Sorry for the lack of experience in my question, but I usually get by with "copy/paste"...LOL
Keeping in mind I am using Access... can I do this?
Clarifying... sorry don't know how to do tables in basic html so have commas
Have this. Pulling from 3 different tables where the member# is unique and joined.
MEMBER, STARTDATE, STATUS, COURSE, COURSEDATE
JohnSmith, 08-01-2013, Active, Workshop1, 10-20-2013
JohnSmith, 08-01-2013, Active, Workshop2, 10-13-2013
JohnSmith, 08-01-2013, Active, Workshop3, 10-28-2013
LaraBentt, 12-01-2012, Inactive, Workshop1, 02-20-2012
LaraBentt, 12-01-2012, Inactive, Workshop2, 02-13-2012
LaraBentt, 12-01-2012, Inactive, Workshop3, 02-28-2012
Want this...
MEMBER, STARTDATE, STATUS, WORKSHOP1, WORKSHOP2, WORKSHOP3
JohnSmith, 08-01-2013, Active, 10-20-2013, 10-13-2013, 10-28-2013
LaraBentt, 12-01-2012, Inactive, 02-20-2012, 02-13-2012, 02-28-2012
Tables columns are basically like this...
Table 1 - tblMember (one - one)
MEMBER, STARTDATE
Table 2 - tblRegStatus (one - one)
MEMBER, STATUS
Table 3 - tblCourses (one to many)
MEMBER, COURSE, COURSEDATE
Hope this explains it better!

Your amendment to your question made it much more clear.
One of the problems you are going to encounter is if you have someone that has registered for the same course, twice. There has to be the understanding that you are only showing the most recent registration per person. Now that we understand that caveat - lets look at how you can build this.
The simplest way of building this is to change the query type from Select to Crosstab. This is done through the Access interface.
For each of the fields in the query, set the Total and Crosstab values to:
MemberName: Total = *Group By* Crosstab = *Row Heading*
StartDate: Total = *Group By* Crosstab = *Row Heading*
Status: Total = *Group By* Crosstab = *Row Heading*
CourseName: Total = *Group By* Crosstab = *Column Heading*
CourseDate: Total = *Max* Crosstab = *Value*
This will result in query results such as:
MemberName StartDate Status Biology English Math
---------- --------- ------ ------- ------- ----
John 10/1/2013 Active 11/14/2013 12/1/2013
Matthew 9/1/2013 Inactive 1/1/2013
Peter 8/7/2013 Active 1/1/2013 4/1/2013
Sam 1/14/2013 Inactive 11/14/2013
William 5/19/2013 Active 1/1/2013 4/1/2013
The advantage to the crosstab is that it will automatically add columns as there is data.
You have to construct your query (the joins) to give you the data that you want however. For example - do you want to show members that have no courses on the list? Do you want to show courses that have no enrollment?
Microsoft has a page on using crosstab queries:
http://office.microsoft.com/en-us/access-help/make-summary-data-easier-to-read-by-using-a-crosstab-query-HA010229577.aspx
If you want to hard code your three columns, you can also manually pivot the data. Again - keep in mind that we are using the Max aggregate, so only the latest courses will show. With a manual pivot you also need to remember that it will be limited to the data you are requesting.
Take your select query, right click and click "Totals" to show the Totals row. You can also click on the Totals icon in the ribbon under Query Tools / Design.
Set up your three columns:
MemberName: Total = *Group By*
StartDate: Total = *Group By*
Status: Total = *Group By*
Now add in a separate field for each course you wish to include. In the "Field" definition enter the following.
Science: IIf([CourseName]="Science",[CourseDate],Null)
Biology: IIf([CourseName]="Biology",[CourseDate],Null)
Math: IIf([CourseName]="Math",[CourseDate],Null)
English: IIf([CourseName]="English",[CourseDate],Null)
Set the "Total" definition value to "Max".
That should get you the results you are looking for.

Related

Using Count and Group By in Power BI

I have a table that contains data about different benefit plans and users enrolled in one or more of those plans. So basically the table contains two columns representing the benefit plan counts and total users enrolled in those plans.
I need to create visualization in Power BI to represent the number of total users enrolled in 1 plan, 2 plans, 3 plans, ...etc.
I wrote the query in sql to get the desired result but not sure how do I do the same in power BI.
Below is my sql query:
SELECT S.PlanCount, COUNT(S.UserName) AS Participants
FROM (
SELECT A.Username, COUNT(*) AS PlanCount
FROM [dbo].[vw_BenefitsCount_Plan_Participants] AS A
GROUP BY A.username
)AS S
GROUP BY S.PlanCount
ORDER BY S.PlanCount
The query result is below image:
So here, PlanCount column represents the total different benefit plans that users are enrolled in. For e.g. the first row means that total of 6008 members are enrolled in only 1 plan, whereas row 2 displays that there are total of 3030 members who are enrolled in total of 2 plans and similarly row 5 means there are only 10 users who are enrolled in total of 6 plans.
I am new to Power BI and trying to understand DAX functions but couldn't find a reasonable example that could help me create my visualization.
I found a something similar here and here but they seem to be more towards single count and group by usage.
Here is a simple example. I have a table of home owners who have homes in multiple cities.
Now in this table, Alex, Dave and Julie have home in 1 city (basically we can say that these 3 people own just 1 home each). Similarly Jim owns a total of 2 homes and Bob and Pam each have 3 homes in total.
Now the output that I need is a table with total number of home owners that own 1 home, 2 homes and so on. So the resulting table in SQL is this.
Where NameCount is basically count of total home owners and Homes is the count of total homes these home owners have.
Please let me know if this helps.
Thanks.
If I understood fine, you have a table like this:
BenefitPlan | User
1 | Max
1 | Joe
2 | Max
3 | Anna
If it's ok, you can simply use a plot bar (for example) where the Axis is BenefitPlan and Value is User. When you drag some column in Value field, it will be grouped automaticaly (like group by in SQL), and by default the groupping method is count.
Hope it helps.
Regards.
You can use DAX to create a summary table from your data table:
https://community.powerbi.com/t5/Desktop/Creating-a-summary-table-out-of-existing-table-assistance/td-p/431485
Once you have counted plans by customer you will then have a field that will enable you to visualize the # of customers with each count.
Mock-up of the code:
PlanSummary = SUMMARIZE('vw_BenefitsCount_Plan_Participants',[Username],COUNT([PLAN_ID])

SSRS query and WHERE with multiple

Being new with SQL and SSRS and can do many things already, but I think I must be missing some basics and therefore bang my head on the wall all the time.
A report that is almost working, needs to have more results in it, based on conditions.
My working query so far is like this:
SELECT projects.project_number, project_phases.project_phase_id, project_phases.project_phase_number, project_phases.project_phase_header, project_phase_expensegroups.projectphase_expense_total, invoicerows.invoicerow_total
FROM projects INNER JOIN
project_phases ON projects.project_id = project_phases.project_id
LEFT OUTER JOIN
project_phase_expensegroups ON project_phases.project_phase_id = project_phase_expensegroups.project_phase_id
LEFT OUTER JOIN
invoicerows ON project_phases.project_phase_id = invoicerows.project_phase_id
WHERE ( projects.project_number = #iProjectNumber )
AND
( project_phase_expensegroups.projectphase_expense_total >0 )
The parameter is for selectionlist that is used to choose a project to the report.
How to have also records that have
( project_phase_expensegroups.projectphase_expense_total ) with value 0 but there might be invoices for that project phase?
Tried already to add another condition like this:
WHERE ( projects.project_number = #iProjectNumber )
AND
( project_phase_expensegroups.projectphase_expense_total > 0 )
OR
( invoicerows.invoicerow_total > 0 )
but while it gives some results - also the one with projectphase_expense_total with value 0, but the report is total mess.
So my question is: what am I doing wrong here?
There is a core problem with your query in that you are left joining to two tables, implying that rows may not exist, but then putting conditions on those tables, which will eliminate NULLs. That means your query is internally inconsistent as is.
The next problem is that you're joining two tables to project_phases that both may have multiple rows. Since these data are not related to each other (as proven by the fact that you have no join condition between project_phase_expensegroups and invoicerows, your query is not going to work correctly. For example, given a list of people, a list of those people's favorite foods, and a list of their favorite colors like so:
People
Person
------
Joe
Mary
FavoriteFoods
Person Food
------ ---------
Joe Broccoli
Joe Bananas
Mary Chocolate
Mary Cake
FavoriteColors
Person Color
------ ----------
Joe Red
Joe Blue
Mary Periwinkle
Mary Fuchsia
When you join these with links between Person <-> Food and Person <-> Color, you'll get a result like this:
Person Food Color
------ --------- ----------
Joe Broccoli Red
Joe Bananas Red
Joe Broccoli Blue
Joe Bananas Blue
Mary Chocolate Periwinkle
Mary Chocolate Fuchsia
Mary Cake Periwinkle
Mary Cake Fuchsia
This is essentially a cross-join, also known as a Cartesian product, between the Foods and the Colors, because they have a many-to-one relationship with each person, but no relationship with each other.
There are a few ways to deal with this in the report.
Create ExpenseGroup and InvoiceRow subreports, that are called from the main report by a combination of project_id and project_phase_id parameters.
Summarize one or the other set of data into a single value. For example, you could sum the invoice rows. Or, you could concatenate the expense groups into a single string separated by commas.
Some notes:
Please, please format your query before posting it in a question. It is almost impossible to read when not formatted. It seems pretty clear that you're using a GUI to create the query, but do us the favor of not having to format it ourselves just to help you
While formatting, please use aliases, Don't use full table names. It just makes the query that much harder to understand.
You need an extra parentheses in your where clause in order to get the logic right.
WHERE ( projects.project_number = #iProjectNumber )
AND (
(project_phase_expensegroups.projectphase_expense_total > 0)
OR
(invoicerows.invoicerow_total > 0)
)
Also, you're using a column in your WHERE clause from a table that is left joined without checking for NULLs. That basically makes it a (slow) inner join. If you want to include rows that don't match from that table you also need to check for NULL. Any other comparison besides IS NULL will always be false for NULL values. See this page for more information about SQL's three value predicate logic: http://www.firstsql.com/idefend3.htm
To keep your LEFT JOINs working as you intended you would need to do this:
WHERE ( projects.project_number = #iProjectNumber )
AND (
project_phase_expensegroups.projectphase_expense_total > 0
OR project_phase_expensegroups.project_phase_id IS NULL
OR invoicerows.invoicerow_total > 0
OR invoicerows.project_phase_id IS NULL
)
I found the solution and it was kind easy after all. I changed the only the second LEFT OUTER JOIN to INNER JOIN and left away condition where the query got only results over zero. Also I used SELECT DISTINCT
Now my report is working perfectly.

Microsoft Access 2010 - Updating Multiple Rows with Different values in ONE query

I have a question about updating multiple rows with different values in MS Access 2010.
Table 1: Food
ID | Favourite Food
1 | Apple
2 | Orange
3 | Pear
Table 2: New
ID | Favourite Food
1 | Watermelon
3 | Cherries
Right now, it looks deceptively simple to execute them separately (because this is just an example). But how would I execute a whole lot of them at the same time if I had, say, 500 rows to update out of 1000 records.
So what I want to do is to update the "Food" table based on the new values from the "New" table.
Would appreciate if anyone could give me some direction / syntax so that I can test it out on MS Access 2010. If this requires VBA, do provide some samples of how I should carry this out programmatically, not manually statement-by-statement.
Thank you!
ADDENDUM (REAL DATA)
Table: Competitors
Columns: CompetitorNo (PK), FirstName, LastName, Score, Ranking
query: FinalScore
Columns: CompetitorNo, Score, Ranking
Note - this query is a query of another query, which in turn, is a query of another query (could there be a potential problem here? There are at least 4 queries before this FinalScore query is derived. Should I post them?)
In the competitors table, all the columns except "Score" and "Ranking" are filled. We would need to take the values from the FinalScore query and insert them into the relevant competitor columns.
Addendum (Brief Explanation of Query)
Table: Competitors
Columns: CompetitorNo (PK), FirstName, LastName, Score, Ranking
Sample Data: AX1234, Simpson, Danny, <blank initially>, <blank initially>
Table: CompetitionRecord
Columns: EventNo (PK composite), CompetitorNo (PK composite), Timing, Bonus
Sample Data1: E01, AX1234, 14.4, 1
Sample Data2: E01, AB1938, 12.5, 0
Sample Data3: E01, BB1919, 13.0, 2
Event No specifies unique event ID
Timing measures the time taken to run 200 metres. The lesser, the better.
Bonus can be given in 3 values (0 - Disqualified, 1 - Normal, 2 - Exceptional). Competitors with Exceptional are given bonus points (5% off their timing).
Query: FinalScore
Columns: CompetitorNo (PK), Score, Ranking
Score is calculated by wins. For example, in the above event (E01), there are three competitors. The winner of the event is BB1919. Winners get 1 point. Losers don't get any points. Those that are disqualified do not receive any points as well.
This query lists the competitors and their cumulative scores (from a list of many events - E01, E02, E03 etc.) and calculates their ranking in the ranking column everytime the query is executed. (For example, a person who wins the most 200m events would be at the top of this list).
Now, I am required to update the Competitors table with this information. The query is rather complex - with all the grouping, summations, rankings and whatnots. Thus, I had to create multiple queries to achieve the end result.
How about:
UPDATE Food
INNER JOIN [New]
ON Food.ID=New.ID
SET Food.[Favourite Food] = New.[Favourite Food]

Beginner SQL question: querying gold and silver tag badges in Stack Exchange Data Explorer

I'm using the Stack Exchange Data Explorer to learn SQL, but I think the fundamentals of the question is applicable to other databases.
I'm trying to query the Badges table, which according to Stexdex (that's what I'm going to call it from now on) has the following schema:
Badges
Id
UserId
Name
Date
This works well for badges like [Epic] and [Legendary] which have unique names, but the silver and gold tag-specific badges seems to be mixed in together by having the same exact name.
Here's an example query I wrote for [mysql] tag:
SELECT
UserId as [User Link],
Date
FROM
Badges
Where
Name = 'mysql'
Order By
Date ASC
The (slightly annotated) output is: as seen on stexdex:
User Link Date
--------------- ------------------- // all for silver except where noted
Bill Karwin 2009-02-20 11:00:25
Quassnoi 2009-06-01 10:00:16
Greg 2009-10-22 10:00:25
Quassnoi 2009-10-31 10:00:24 // for gold
Bill Karwin 2009-11-23 11:00:30 // for gold
cletus 2010-01-01 11:00:23
OMG Ponies 2010-01-03 11:00:48
Pascal MARTIN 2010-02-17 11:00:29
Mark Byers 2010-04-07 10:00:35
Daniel Vassallo 2010-05-14 10:00:38
This is consistent with the current list of silver and gold earners at the moment of this writing, but to speak in more timeless terms, as of the end of May 2010 only 2 users have earned the gold [mysql] tag: Quassnoi and Bill Karwin, as evidenced in the above result by their names being the only ones that appear twice.
So this is the way I understand it:
The first time an Id appears (in chronological order) is for the silver badge
The second time is for the gold
Now, the above result mixes the silver and gold entries together. My questions are:
Is this a typical design, or are there much friendlier schema/normalization/whatever you call it?
In the current design, how would you query the silver and gold badges separately?
GROUP BY Id and picking the min/max or first/second by the Date somehow?
How can you write a query that lists all the silver badges first then all the gold badges next?
Imagine also that the "real" query may be more complicated, i.e. not just listing by date.
How would you write it so that it doesn't have too many repetition between the silver and gold subqueries?
Is it perhaps more typical to do two totally separate queries instead?
What is this idiom called? A row "partitioning" query to put them into "buckets" or something?
Requirement clarification
Originally I wanted the following output, essentially:
User Link Date
--------------- -------------------
Bill Karwin 2009-02-20 11:00:25 // result of query for silver
Quassnoi 2009-06-01 10:00:16 // :
Greg 2009-10-22 10:00:25 // :
cletus 2010-01-01 11:00:23 // :
OMG Ponies 2010-01-03 11:00:48 // :
Pascal MARTIN 2010-02-17 11:00:29 // :
Mark Byers 2010-04-07 10:00:35 // :
Daniel Vassallo 2010-05-14 10:00:38 // :
------- maybe some sort of row separator here? can SQL do this? -------
Quassnoi 2009-10-31 10:00:24 // result of query for gold
Bill Karwin 2009-11-23 11:00:30 // :
But the answers so far with a separate column for silver and gold is also great, so feel free to pursue that angle as well. I'm still curious how you'd do the above, though.
Is this a typical design, or are there much friendlier schema/normalization/whatever you call it?
Sure, you could add a type code to make it more explicit. But when you consider that one can not get a gold badge before a silver one, the date stamp makes a lot of sense to differentiate between them.
In the current design, how would you query the silver and gold badges separately? GROUP BY Id and picking the min/max or first/second by the Date somehow?
Yes - joining onto a derived table (AKA inline view) that is a list of users & the minimum date would return the silver badges. Using HAVING COUNT(*) >= 1 would work too. You'd have to use a combination of GROUP BY and HAVING COUNT(*) = 2` to get gold badges - the max date doesn't ensure that there are more than one record for a userid...
How can you write a query that lists all the silver badges first then all the gold badges next?
Sorry - by users, or all silvers first and then golds? The former might be done simply by using ORDER BY t.userid, t.date; the latter I'd likely use analytic functions (IE: ROW_NUMBER(), RANK())...
Is it perhaps more typical to do two totally separate queries instead?
See above about how vague your requirements are, to me anyways...
What is this idiom called? A row "partitioning" query to put them into "buckets" or something?
What you're asking about is referred to by the following synonyms: Analytic, Windowing, ranking...
You'd do something like this and rely only on date or count in an aggregate.
Arguably, it also makes no sense to query silver followed by gold, but rather get data side by side like this:
Unfortunately, you haven't really specified what you want, but a good starting point for aggregates is to express it in plain English
Example: "Give me dates of silver and gold badge awards per user for tag mysql". Which this does:
SELECT
UserId as [User Link],
min(Date) as [Silver Date],
case when count(*) = 1 THEN NULL ELSE max(date) END
FROM
Badges
Where
Name = 'mysql'
group by
UserId
Order By
case when count(*) = 1 THEN NULL ELSE max(date) END DESC, min(Date)
Edit, after update:
Your desired output is not really SQL: it's 2 separate recordsets. The separator is a no-go. As a setb based operation, there is no "natural" order so this introduces one:
SELECT
UserId as [User Link],
min(Date) as [Date],
0 as dummyorder
FROM
Badges
Where
Name = 'mysql'
group by
UserId
union all
select
UserId as [User Link],
max(Date) as [Date],
1 as dummyorder
FROM
Badges
Where
Name = 'mysql'
group by
UserId
having
count(*) = 2
Order By
dummyorder, Date

Complex SQL query with group by and two rows in one

Okay, I need help. I'm usually pretty good at SQL queries but this one baffles me. By the way, this is not a homework assignment, it's a real situation in an Access database and I've written the requirements below myself.
Here is my table layout. It's in Access 2007 if that matters; I'm writing the query using SQL.
Id (primary key)
PersonID (foreign key)
EventDate
NumberOfCredits
SuperCredits (boolean)
There are events that people go to. They can earn normal credits, or super credits, or both at one event. The SuperCredits column is true if the row represents a number of super credits earned at the event, or false if it represents normal credits.
So for example, if there is an event which person 174 attends, and they earn 3 normal credits and 1 super credit at the event, the following two rows would be added to the table:
ID PersonID EventDate NumberOfCredits SuperCredits
1 174 1/1/2010 3 false
2 174 1/1/2010 1 true
It is also possible that the person could have done two separate things at the event, so there might be more than two columns for one event, and it might look like this:
ID PersonID EventDate NumberOfCredits SuperCredits
1 174 1/1/2010 1 false
2 174 1/1/2010 2 false
3 174 1/1/2010 1 true
Now we want to print out a report. Here will be the columns of the report:
PersonID
LastEventDate
NumberOfNormalCredits
NumberOfSuperCredits
The report will have one row per person. The row will show the latest event that the person attended, and the normal and super credits that the person earned at that event.
What I am asking of you is to write, or help me write, the SQL query to SELECT the data and GROUP BY and SUM() and whatnot. Or, let me know if this is for some reason not possible, and how to organize my data to make it possible.
This is extremely confusing and I understand if you do not take the time to puzzle through it. I've tried to simplify it as much as possible, but definitely ask any questions if you give it a shot and need clarification. I'll be trying to figure it out but I'm having a real hard time with it, this is grouping beyond my experience...
Create a query/view of the following (say its called PersonLastEvents):
select PersonId, max(EventDate) as LastEventDate
from Events
group by PersonId
Then you can get the data you need with the following. I'm not fully familiar with Access, so you may need to modify some of the syntax, but hopefully this will give you an approach.
select l.PersonId, l.LastEventDate,
sum(case when e.SuperCredits = 'false' then e.NumberOfCredits end)
as NumberOfNormalCredits
sum(case when e.SuperCredits = 'true' then e.NumberOfCredits end)
as NumberOfSuperCredits
from PersonLastEvents l
join Events e on l.PersonId = e.PersonId and l.LastEventDate = l.EventDate
group by l.PersonId, l.LastEventDate
As an aside, it may be easier to change your table to have two number columns (NormalCredits, SuperCredits) as it allows you to simply sum() the columns as required.