MS Access average a value based on other column data - sql

So my data looks something like this:
Smpl_id Plate_id CT_Value
1 1 27
1 1 32
2 1 56
2 1 49
1 2 40
1 2 36
2 2 58
2 2 64
I would like to design a query that returns averages of CT_Value of each sample in a plate, so it would look like this:
Smpl_id Plate_id Avg_CT
1 1 29.5
2 1 52.5
1 2 38
2 2 61
I have tried
Avg_CT: DAvg("[CT_Value]","[qPCR_sample_data]","[Plate_id] = '" & [Plate_id] & "'" And "[Smpl_is] = '" & [Smpl_id] & "'")
But that just results in:
Smpl_id Plate_id CT_Value
1 1 45.25
1 1 45.25
2 1 45.25
2 1 45.25
1 2 45.25
1 2 45.25
2 2 45.25
2 2 45.25
I can't just list the plate or sample id numbers because this is actually a long list that is continually growing. I also need to use these average numbers in future calculations (that I have already figured out how to do).
Also, I have just started using MS Access (designing a brand new database), so I kinda understand SQL but have very little actual experience in it.
Thank you!

You will need to use a group by query.
Create a new query, and add the table (in my example I've called it tblSample).
Add the three fields, Smpl_id, Plate_id and CT_Value to the query grid.
On the Query Design memubar, click on the button labelled "Totals".
This introduces a new row in the query grid called "Total", with all three fields having it set to "Group By".
Simply change the "Group By" for CT_Value to "Avg", and run the query to get the results you are after:
Regards,

You should be able to use simple aggregation such as:
select t.smpl_id, t.plate_id, avg(t.ct_value) as avg_ct
from qpcr_sample_data t
group by t.smpl_id, t.plate_id

Related

Selection that repeats a group of columns based on a separate column having a different value

Hello and thanks for having a look!
I'm trying to make a complex selection from a prior query and I'm having a hard time locating a solution, in part because I'm having a hard time describing what I'm after or what to search for. Here's the rub:
What I have ([table1]):
identifier
month
item 1
item 2
xyz-1
10
0
0
xyz-2
10
0
0
xyz-1
11
1
1
xyz-2
11
1
1
What I would like if possible:
identifier
item 1 - 10
item 2 - 10
item 1 - 11
item 2 - 11
xyz-1
0
0
1
1
xyz-2
0
0
1
1
With the goal being that I have a set of Items for every month in the year (above example showing only Oct and Nov). I feel like a Group By and Join solution is what I need, but I'm stuck after spending all day on this.
Any help is appreciated!
Update 1 - Close Solution:
Using a combination of suggestions from two contributors below, I was able to rewrite my original query that generated my starting table above.
I had been running this query:
TRANSFORM First([Points]) AS ItemPoints
SELECT identifier, month
FROM [source]
GROUP identifier, month
PIVOT name;
But this created a column for month which is pretty obvious in hindsight.
The solution was the following query:
TRANSFORM First([source].Points) AS ItemPoints
SELECT [source].identifier
FROM [itemNames], [source]
GROUP BY [source].identifier
ORDER BY ScoreMonth & [itemNames].ItemId
PIVOT ScoreMonth & [itemNames].ItemId;
Where [itemNames] is a query that returns a list of unique item names, the "item 1", "item 2" bit.
This resulted in the following table:
identifier
10item 1
10item 2
11item 1
11item 2
xyz-1
0
0
1
1
xyz-2
0
0
1
1
Which I can work with :)
Update 2 - Wasn't Solved
Soon after I posted that the solution was found, I realized that the values were incorrect because of the aggregate function on the Transform line. I'm looking into this again, and the solution presented below with the DlookUp() function.
Update 3 - Solution
I found that the problem with my Transform query was that the ORDER BY and PIVOT lines needed to reference the [source] table and not the [itemNames] table. I also changed the First() function to Min(), but either work :)
TRANSFORM Min([source].Points) AS ItemPoints
SELECT [source].identifier
FROM [source]
GROUP BY [source].identifier
ORDER BY ScoreMonth & '_' & [source].ItemId
PIVOT ScoreMonth & '_' & [source].ItemId;
What your are trying to do is called a cross-tab query. However your query has 2 column headings Month and Item. Month is invisible. Access and Excel only allow 1 column heading in a cross-tab query. So my solution is to manually generate the 2 column cross-tab.
So for the manual cross-tab we need to do a cross-join query to generate all the rows and columns we will need. Then we use a calculated-field and the dlookup function to insert the correct value from Table1 into the correct cell in the upcoming cross-tab querie's root query.
ItemNames is a table of all the item names, Months (here 2 months), Identifiers is all identifiers. Since we cant have 2 columns with the same name we are going to use ItemMonth as a work around.
Value: Nz(DLookUp("item1","Table1","identifier = '" & [identifier] & "' AND monthnumber = " & [MonthNumber]),0)
ItemMonth: [MonthNumber] & [ItemName]
'Table 1
ID identifier monthnumber item1 item2
3 xyz-1 10 0 0
4 xyz-2 10 0 0
5 xyz-1 11 1 1
6 xyz-2 11 1 1
'after cross join : query1 in picture
MonthNumber ItemName identifier Value ItemMonth
10 Item 1 xyz-1 0 10Item 1
11 Item 1 xyz-1 1 11Item 1
10 Item 2 xyz-1 0 10Item 2
11 Item 2 xyz-1 1 11Item 2
10 Item 1 xyz-2 0 10Item 1
11 Item 1 xyz-2 1 11Item 1
10 Item 2 xyz-2 0 10Item 2
11 Item 2 xyz-2 1 11Item 2
The cross-tab set up is as simple as it gets. The cross-tab is a type of totals query so pay attention to the summary functions:
'result of our cross-tab query but the column names are still wrong so we will fix that with a report
identifier 10Item 1 10Item 2 11Item 1 11Item 2
xyz-1 0 0 1 1
xyz-2 0 0 1 1
To generate the repot I just selected the cross-tab query and hit report. Then went into design mode and edited all the column labels. If you have to do this whole process frequently or have a whole lot of items use VBA to auto adjust the report labels.
Aside 1. In Access, cross-tab queries bug-out if they are based on even slightly complicated queries. If your cross-tab is based on a query and it doesn't work try turning the cross-tab's query into a table with a make-table query. Then base the cross-tab on the new table.
Aside 2. I suggest Looking at the cross-tab as only a way to view your data. Every time you add or subtract an item to this data that results in adding or subtracting 12 columns to the cross-tab. that means you have to adjust any reports and forms based on a cross-tab every time the items change. Way to much work.

Pivot on multiple fields and export from Access

I have built an access application for a manufacturing plant and have provided them with a report that lists different data points along a process. I have a way to generate a report that looks like the following.
Batch Zone Value1 Value 2 etc.
25 1 5 15
25 2 12 31
26 1 6 14
26 2 10 32
However, there is demand to view the data in a different format. They would like one line per batch, with all data horizontal. Like this...
Zone 1 Zone 2
Batch Value1 Value2 Value1 Value2
25 5 15 12 31
26 6 14 10 32
In all there will be 157 columns, if displayed as in the second example. There are 7 unique field names, but the rest are 14 different data types that are repeated. I can't get a query to display the data in the format the they want, do to the fact that the field names are the same, but it is not hard to do it the first way. I can use VBA to insert the data into a table, but I can't use duplicate field names, so when I go to export this to Excel the field names won't mean anything, and there can't be sections (like zone1, zone2, etc.) I can link a report to this, but the report width can only be 22", so I would have to export and then do some vba handling of the excel sheet on the other end to display in a legible way.
I can get the data into format #1, is there some way I can get the data to display in one long row based on batch number? Does anyone else have a great idea of how this is doable?
Open to any suggestions. Thanks!
In your question you say that
I have a way to generate a report that looks like the following
and then list the data as
Batch Zone Value1 Value2
----- ---- ------ ------
25 1 5 15
25 2 12 31
26 1 6 14
26 2 10 32
Now perhaps the data may already be in "un-pivoted" form somewhere (with different Values in separate rows), but if not then you would use something like the following query to achieve that
SELECT
[Batch],
"Zone" & [Zone] & "_" & "Value1" AS [ValueID],
[Value1] AS [ValueValue]
FROM BatchDataByZone
UNION ALL
SELECT
[Batch],
"Zone" & [Zone] & "_" & "Value2" AS [ValueID],
[Value2] AS [ValueValue]
FROM BatchDataByZone
...returning:
Batch ValueID ValueValue
----- ------------ ----------
25 Zone1_Value1 5
25 Zone2_Value1 12
26 Zone1_Value1 6
26 Zone2_Value1 10
25 Zone1_Value2 15
25 Zone2_Value2 31
26 Zone1_Value2 14
26 Zone2_Value2 32
However you get to that point, if you save that query as [BatchDataUnpivoted] then you could use a simple Crosstab Query to "string out" the values for each batch...
TRANSFORM Sum(BatchDataUnpivoted.[ValueValue]) AS SumOfValueValue
SELECT BatchDataUnpivoted.[Batch]
FROM BatchDataUnpivoted
GROUP BY BatchDataUnpivoted.[Batch]
PIVOT BatchDataUnpivoted.[ValueID];
...returning...
Batch Zone1_Value1 Zone1_Value2 Zone2_Value1 Zone2_Value2
----- ------------ ------------ ------------ ------------
25 5 15 12 31
26 6 14 10 32

SQL comparing two tables with common id but the id in table 2 could being in two different columns

Given the following SQL tables:
Administrators:
id Name rating
1 Jeff 48
2 Albert 55
3 Ken 35
4 France 56
5 Samantha 52
6 Jeff 50
Meetings:
id originatorid Assitantid
1 3 5
2 6 3
3 1 2
4 6 4
I would like to generate a table from Ken's point of view (id=3) therefore his id could be possibly present in two different columns in the meetings' table. (The statement IN does not work since I introduce two different field columns).
Thus the ouput would be:
id originatorid Assitantid
1 3 5
2 6 3
If you really just need to see which column Ken's id is in, you only need an OR. The following will produce your example output exactly.
SELECT * FROM Meetings WHERE originatorid = 3 OR Assistantid = 3;
If you need to take the complex route and list names along with meetings, an OR in your join's ON clause should work here:
SELECT
Administrators.name,
Administrators.id,
Meetings.originatorid,
Meetings.Assistantid
FROM Administrators
JOIN Meetings
ON Administrators.id = Meetings.originatorid
OR Administrators.id = Meetings.Assistantid
Where Administrators.name = 'Ken'

MS Access CrossTab query - across 3 tables

I have the following 3 tables:
1) Sweetness Table
FruitIndex CountryIndex Sweetness
1 1 10
1 2 20
1 3 400
2 1 50
2 2 123
2 3 1
3 1 49
3 2 40
3 3 2
2) Fruit Name Table
FruitIndex FruitName
1 Apple
2 Orange
3 Peaches
3) Country Name Table
CountryIndex CountryName
1 UnitedStates
2 Canada
3 Mexico
I'm trying to perform a CrossTab SQL query to end up with:
Fruit\Country UnitedStates Canada Mexico
Apple 10 20 400
Orange 50 123 1
Peaches 49 40 2
The challenging part is to label the rows/columns with the relevant names from the Name tables.
I can use MS Access to design 2 queries,
create the joins the fruit/country names table with the Sweetness table
perform crosstab query
However I'm having trouble doing this in a single query. I've attempted nesting the 1st query's SQL into the 2nd, but it doesn't seem to work.
Unfortunately, my solution needs to be be wholly SQL, as it is an embedded SQL query (cannot rely on query designer in MS Access, etc.).
Any help greatly appreciated.
Prembo.
How about:
TRANSFORM First(Sweetness.Sweetness) AS FirstOfSweetness
SELECT Fruit.FruitName
FROM (Sweetness
INNER JOIN Fruit
ON Sweetness.FruitIndex = Fruit.FruitIndex)
INNER JOIN Country
ON Sweetness.CountryIndex = Country.CountryIndex
GROUP BY Fruit.FruitName
PIVOT Country.CountryName;
I hate to rely on an outside post and present it as my answer, but this is a pretty steep topic and I can't do it justice. So I suggest you look at this article.

Sql Server Row Concatenation

I have a table (table variable in-fact) that holds several thousand (50k approx) rows of the form:
group (int) isok (bit) x y
20 0 1 1
20 1 2 1
20 1 3 1
20 0 1 2
20 0 2 1
21 1 1 1
21 0 2 1
21 1 3 1
21 0 1 2
21 1 2 2
And to pull this back to the client is a fairly hefty task (especially since isok is a bit). What I would like to do is transform this into the form:
group mask
20 01100
21 10101
And maybe go even a step further by encoding this into a long etc.
NOTE: The way in which the data is stored currently cannot be changed.
Is something like this possible in SQL Server 2005, and if possible even 2000 (quite important)?
EDIT: I forgot to make it clear that the original table is already in an implicit ordering that needs to be maintained, there isnt one column that acts as a linear sequence, but rather the ordering is based on two other columns (integers) as above (x & y)
You can treat the bit as a string ('0', '1') and deploy one of the many string aggregate concatenation methods described here: http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/