Related
Yes, I know this seems simple:
SELECT DISTINCT(...)
Except, it apparently isn't
Here is my actual Query:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS,
IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune,
IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical,
IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther,
IIf([DecReason]=7,1,0) AS YesAlready
FROM
EmployeeInformation
INNER JOIN (CompletedTrainings
LEFT JOIN DeclinationReasons ON CompletedTrainings.DecReason = DeclinationReasons.ReasonID)
ON EmployeeInformation.ID = CompletedTrainings.Employee
GROUP BY
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
CompletedTrainings.DecShotDate,
CompletedTrainings.DecShotLocation,
CompletedTrainings.DecReason,
CompletedTrainings.DecExplanation,
IIf([DecShotLocation]="MCS","Yes","No"),
IIf([DecReason]=1,1,0),
IIf([DecReason]=2,1,0),
IIf([DecReason]=3,1,0),
IIf([DecReason]=4,1,0),
IIf([DecReason]=5,1,0),
IIf([DecReason]=6,1,0),
IIf([DecReason]=7,1,0)
HAVING
((((EmployeeInformation.Active) Like -1)
AND ((CompletedTrainings.DecShotDate + 365 >= DATE())
OR (CompletedTrainings.DecShotDate IS NULL))));
This is Joining a few tables (obviously) in order to get a number of records. The problem is that if someone is duplicated on the table with a NULL in one of the date fields, and a date in another field, it pulls both the NULL and the DATE, or pulls multiple NULLS it might pull multiple dates but those are not present right at the moment.
I need the Nulls, they are actual data in this particular case, but if someone has a date and a NULL I need to pull only the newest record, I thought I could add MAX(RecordID) from the table, but that didn't change the results of the query either.
That code:
SELECT
DeclinationReasons.Reason,
EmployeeInformation.ID,
EmployeeInformation.Employee,
EmployeeInformation.Active,
MAX(CompletedTrainings.RecordID),
CompletedTrainings.DecShotDate
...
And it returned the same issue, Duplicated EmployeeInformation.ID with different DecShotDate values.
Currently it returns:
ID
Active
DecShotDate
etc. x a bunch
1
-1
date date
whatever goes
2
-1
in these
2
-1
date date
columns
These are being used in a report, that is to determine the total number of employees who fit the criteria of the report. The NULLs in DecShotDate are needed as they show people who did not refuse to get a flu vaccine in the current year, while the dates are people who did refuse.
Now I have come up with one simple solution, I could add a column to the CompletedTrainings Table that contains a date or other value, and add that to the HAVING statement. This might be the right solution as this is a yearly training questionnaire that employees have to fill out. But I am asking for advice before doing this.
Am I right in thinking I need to add a column to filter by so that older data isn't being pulled, or should I be able to do this by pulling recordID, and did I just bork that part of the query up?
Edited to add raw table views:
EmployeeInformation Table:
ID
Last
First
empID
Active
Termdate
DoH
Title
PT/FT/PD
PI
1
Doe
Jane
982
-1
date
Sr
PD
X
2
Roe
John
278
0
date
date
Jr
PD
X
3
Moe
Larry
1232
-1
date
Sr
FT
X
4
Zoe
Debbie
1424
-1
date
Sr
PT
X
DeclinationReasons Table:
ReasonID
Reason
1
Allergy
2
Already got it
3
Illness
CompletedTrainings Table:
RecordID
Employee
Training
...
DecShotdate
DecShotLocation
DecShotReason
DecExp
1
1
4
date
location
2
text
2
1
4
3
2
4
4
3
4
date
location
3
text
5
3
4
date
location
1
text
6
4
4
After some serious soul searching, I decided to use another column and filter by that.
In the end my query looks like this:
SELECT *
FROM (
(
SELECT RecordID, DecShotDate, DecShotLocation, DecReason, DecExplanation, Employee,
IIf([DecShotLocation]="MCS","Yes","No") AS YesMCS, IIf([DecReason]=1,1,0) AS YesAllergy,
IIf([DecReason]=2,1,0) AS YesImmune, IIf([DecReason]=3,1,0) AS YesAdverse,
IIf([DecReason]=4,1,0) AS YesMedical, IIf([DecReason]=5,1,0) AS YesSpiritual,
IIf([DecReason]=6,1,0) AS YesOther, IIf([DecReason]=7,1,0) AS YesAlready
FROM CompletedTrainings WHERE (CompletedDate > DATE() - 365 ) AND (Training = 69)) AS T1
LEFT JOIN
(
SELECT ID, Active FROM EmployeeInformation) AS T2 ON T1.Employee = T2.ID)
LEFT JOIN
(
SELECT Reason, ReasonID FROM DeclinationReasons) AS T3 ON T1.DecReason = T3.ReasonID;
This may not have been the best solution, but it did exactly what I needed. Which is to get the information by latest entry into the database.
Previously I had tried to use MAX(), DISTINCT(), etc. but always had a problem of multiple records being retrieved. In this case, I intentionally SELECT the most recent records first, then join them to the results of the next query, and so on. Until I have all the required data for my report.
I write this in hopes someone else finds it useful. Or even better if someone tells me why this is wrong, so as to improve my own skills.
I have two tables Medication and Inventory. I'm trying to SELECT all the below details from both tables but there are multiple listings of medication ids with different BRANCH_NO also in the INVENTORY table (the primary key in INVENTORY is actually BRANCH_NO, MEDICATION_ID composite key)
I need to total up the various medication_IDs and also join the tables in one SELECT command and display all the infomation for each med (there are 5) with a total sum of each med at the end of each row. But im getting all muddled trying Group by and Sum and at one point partition. Help please I'm new to this.
Below is the latest non working version - but it doesn't display
Medication Name
Medication Desc
Manufacturer
Pack Size
like i chanced it might.
SELECT I.MEDICATION_ID,
SUM(I.STOCK_LEVEL)
FROM INVENTORY I
INNER JOIN (SELECT MEDICATION_NAME, SUBSTR(MEDICATION_DESC,1,20) "Medication Description",
MANUFACTURER, PACK_SIZE FROM MEDICATION) M ON MEDICATION_ID=I.MEDICATION_ID
GROUP BY I.MEDICATION_ID;
For the data imagine I want this sort of output:
MEDICATION_ID MEDICATION_NAME STOCK_LEVEL OtherColumns.....
1 Alpha 10
2 Bravo 20
3 Charlie 20
1 Alpha 30
4 Delta 10
5 Echo 20
5 Echo 40
2 Bravo 10
grouping and totalling into this:
MEDICATION_ID MEDICATION_NAME STOCK_LEVEL OtherColumns.....
1 Alpha 40
2 Bravo 30
3 Charlie 20
4 Delta 10
5 Echo 60
I can get this when its just one table but when Im trying to join tables and also SELECT things its just not working.
Thanks in advance guys. I appreciate it may be a simple solution, but it will be a big help.
You need to write explicitly all non-aggregated columns into both SELECT and GROUP BY lists ( Btw, no need to use a nested query, and if it's the case MEDICATION_ID column is missing in it ) :
SELECT I.MEDICATION_ID, M.MEDICATION_NAME, SUM(I.STOCK_LEVEL) AS STOCK_LEVEL,
SUBSTR(M.MEDICATION_DESC,1,20) "Medication Description", M.MANUFACTURER, M.PACK_SIZE
FROM INVENTORY I
JOIN MEDICATION M ON M.MEDICATION_ID = I.MEDICATION_ID
GROUP BY I.MEDICATION_ID, M.MEDICATION_NAME, SUBSTR(M.MEDICATION_DESC,1,20),
M.MANUFACTURER, M.PACK_SIZE;
This way, you'll be able to return all the listed columns.
This question might seem generic, but it's rather complicated.
Let's start with the basics of software:
MS Access 2016
MS SQL ver. 17.7
DAQFactory 17.1
DAQFactory is a SCADA software, which I use to measure and store data from multiple temperature sensors. I use an "Export Set" to export the sensor data to my MSSQL Database. I sample the sensor data once a minute, generating 1 row of sensor data. I've set it up to create a new table for each sample (because I only need to sample 10 times/from 1 to 10 minutes, and that way I don't need to change the names of my tables all the time).
I have 6 temperature sensors, that DAQFactory export in a format like this:
The MS SQL database is simply just a carrier/channel for my data to go from DAQFactory to MS Access, and therefore I do not have any problems with the database.
This is a School Project and I'm in over my head. The client I'm making the software package for wants to collect his data in a report with other types of data. Therefore I need to put the sensor data into a form like this:
I use MS Access to create the report and to collect data from my database. I've tried several types of queries, but i can't get it to work like I want.
The problem is that the table in the database and in the report have the opposite placement of row and columns and I'm not able to switch it in a query in Access (also called a transpose).
I've looked at some of these solutions:
https://access-programmers.co.uk/forums/showthread.php?t=169794
converting column names to use as row fields in Access
Access - transpose some column data into row records
JOIN functions
PIVOT functions
But I can't get it to work.
Export sets:
All my export sets include the same columns:
[TheTime],
[T_01],
[T_02],
[T_03],
[T_04],
[T_05],
[T_06]
The export sets are called:
dbo.Temp_1min
dbo.Temp_2min
dbo.Temp_3min
dbo.Temp_4min
and so on up to 10.
When importing this to Access, [TheTime] becomes the primary key, and all samples that are recorded, are recorded on the exact same second, so this is naturally the ID of the tables.
Here is the code I'm using to show my data. I am using the "Totals: Last" so that the only thing that shows in my table is the last value from each table and sensor. Excuse the code, it's formatted in Norwegian but the only difference is "SisteAv" which means "LastOf" e.g the "Totals: Last" function.
Code to get the last value from the "dbo_Temp_1min" table, this query is called "Temp_Samples1":
SELECT Last(dbo_Temp_1min.TheTime) AS SisteAvTheTime, Last(dbo_Temp_1min.T_01) AS SisteAvT_01, Last(dbo_Temp_1min.T_02) AS SisteAvT_02, Last(dbo_Temp_1min.T_03) AS SisteAvT_03, Last(dbo_Temp_1min.T_04) AS SisteAvT_04, Last(dbo_Temp_1min.T_05) AS SisteAvT_05, Last(dbo_Temp_1min.T_06) AS SisteAvT_06
FROM dbo_Temp_1min;
Code to put several tables into one:
SELECT [SisteAvTheTime], [SisteAvT_01], [SisteAvT_02], [SisteAvT_03], [SisteAvT_04], [SisteAvT_05], [SisteAvT_06]
FROM Temp_Samples1
UNION
SELECT [SisteAvTheTime], [SisteAvT_01], [SisteAvT_02], [SisteAvT_03], [SisteAvT_04], [SisteAvT_05], [SisteAvT_06]
FROM Temp_Samples2;
This is the current result I am getting and the column and rows are opposite of what I need:
To clarify what I need:
1)The first column to list the names of all the temperature sensors (T_01, T_02, T_03 etc.).
2) The second column to list the last row of sensor data from table 1 (dbo.Temp_1min).
3) The third column to list the last row of sensor data from table 2 (dbo.Temp_2min)
4) The fourth column to list the last row of sensor data from table 3 (dbo.Temp_3min)
etc...
The column "TheTime" is not relevant for the end result and should be hidden, since the time depends on the names on the tables (1min, 2min, 3min etc.)
As per request the data contained in MS SQL database for [dbo.Temp_1min]:
TheTime T_01 T_02 T_03 T_04 T_05 T_06
----------------------- ------------- ------------- ------------- ------------- ------------- -------------
2018-05-24 15:18:37.000 -0,080911 -0,051013 0,090363 0,034291 -0,096702 -0,016438
2018-05-25 15:04:22.010 0,095227 0,021559 -0,099226 -0,003178 0,099815 -0,015269
2018-05-25 15:04:23.003 0,095226 0,021562 -0,099226 -0,003181 0,099815 -0,015265
2018-05-25 20:06:17.000 0,061521 0,072766 -0,075043 -0,058863 0,085937 0,042978
2018-05-25 20:12:47.000 60,50084 73,64336 -74,18618 -59,89857 85,27211 44,13688
2018-05-25 20:12:47.000 60,50084 73,66345 -74,16626 -59,92236 85,25659 44,16353
2018-05-25 20:06:17.000 0,061521 0,072787 -0,075024 -0,058887 0,085922 0,043005
2018-05-25 20:10:40.003 60,83407 73,37933 -74,46661 -59,5624 85,49031 43,7604
2018-05-25 20:10:40.003 60,83407 73,37933 -74,44677 -59,58627 85,47488 43,78712
2018-05-25 20:23:07.003 58,85883 75,03191 -72,77819 -61,54791 84,16943 45,98995
(10 rows affected)
UNION query is limited to 50 SELECT lines. You have 10 tables and 6 sensors which means 60 SELECT lines. If there were less of either, a single UNION could merge the tables and then a CROSSTAB could pivot the data. Instead, do 10 UNION queries and JOIN them. Here is example of first UNION.
SELECT TOP 1 TheTime, T_01 AS Min1, "T01" AS Sensor, "1Min" AS Source FROM Temp_1min ORDER BY TheTime DESC
UNION (SELECT TOP 1 TheTime, T_02, "T02", "1Min" FROM Temp_1min ORDER BY TheTime DESC)
UNION (SELECT TOP 1 TheTime, T_03, "T03", "1Min" FROM Temp_1min ORDER BY TheTime DESC)
UNION (SELECT TOP 1 TheTime, T_04, "T04", "1Min" FROM Temp_1min ORDER BY TheTime DESC)
UNION (SELECT TOP 1 TheTime, T_05, "T05", "1Min" FROM Temp_1min ORDER BY TheTime DESC)
UNION (SELECT TOP 1 TheTime, T_06, "T06", "1Min" FROM Temp_1min ORDER BY TheTime DESC);
Now pick one of the queries to be the 'master' and join the other 9 to it. Here is example with only 2 queries.
SELECT [Q1].Sensor, [Q1].Min1, [Q2].Min2
FROM Q2 INNER JOIN Q1 ON [Q2].Sensor = [Q1].Sensor
ORDER BY [Q1].Sensor;
The output (used same sample data for both tables):
Sensor Min1 Min2
T01 58.85883 58.85883
T02 75.03191 75.03191
T03 -72.77819 -72.77819
T04 -61.54791 -61.54791
T05 84.16943 84.16943
T06 45.98995 45.98995
If this is too unmanageable and/or performs so slowly as to be impractical, only other approach would be with VBA. See example of similar requirement in https://www.access-programmers.co.uk/forums/showthread.php?t=299864.
Hello can anyone help me with a query where you select all columns and then count the content of the columns. Not sure how this could be achieved can someone shed some light on that.
For example I have a table that returns number of tickets but those tickets can be more than one so I would like to select all the tickets depending on a variable and then count the contents of it like this:
Booking ID | Tickets | variable
1 2
2 1
3 5
How would I go about to count the contents of for example booking 1 and 3 so that the result will be 7
Thank you.
SELECT SUM(Tickets) FROM your_table WHERE Booking_ID IN (1,3)
Platform: SQL Server 2005 Express
Disclaimer: I’m quite a novice to SQL and so if you are happy to help with what may be a very simple question, then I won’t be offended if you talk slowly and use small words :-)
I have a table where I want to SUM the contents of multiple rows. However, I want to SUM one column only for the first occurrence of text in a different column.
Table schema for table 'tblMain'
fldOne {varchar(100)} Example contents: “Dandelion“
fldTwo {varchar(8)} Example contents: “01:00:00” (represents hh:mm:ss)
fldThree {numeric(10,0)} Example contents: “65”
Contents of table:
Row number fldOne fldTwo fldThree
------------------------------------------------
1 Dandelion 01:00:00 99
2 Daisy 02:15:00 88
3 Dandelion 00:45:00 77
4 Dandelion 00:30:00 10
5 Dandelion 00:15:00 200
6 Rose 01:30:00 55
7 Daisy 01:00:00 22
etc. ad nausium
If I use:
Select * from tblMain where fldTwo < ’05:00:00’ order by fldOne, fldTwo desc
Then all rows are correctly returned, ordered by fldOne and then fldTwo in descending order (although in the example data I've shown, all the data is already in the correct order!)
What I’d like to do is get the SUM of each fldThree, but only from the first occurrence of each fldOne.
So, SUM the first Dandelion, Daisy and Rose that I come across. E.g.
99+88+55
At the moment, I’m doing this programmatically; return a RecordSet from the Select statement above, and MoveNext through each returned row, only adding fldThree to my ‘total’ if I’ve never seen the text from fldOne before. It works, but most of the Select queries return over 100k rows and so it’s quite slow (slow being a relative term – it takes about 50 seconds on my setup).
The actual select statement (selecting about 100k rows from 1.5m total rows) completes in under a second which is fine. The current programatic loop is quite small and tight, it's just the number of loops through the RecordSet that takes time. I'm using adOpenForwardOnly and adLockReadOnly when I open the record set.
This is a routine that basically runs continuously as more data is added, and also the fldTwo 'times' vary, so I can't be more specific with the Select statement.
Everything that I’ve so far managed to do natively with SQL seems to run quickly and I’m hoping I can take the logic (and work) away from my program and get SQL to take the strain.
Thanks in advance
The best way to approach this is with window functions. These let you enumerate the rows within a group. However, you need some way to identify the first row. SQL tables are inherently unordered, so you need a column to specify the ordering. Here are some ideas.
If you have an id column, which is defined as an identity so it is autoincremented:
select sum(fldThree)
from (select m.*,
row_number() over (partition by fldOne order by id) as seqnum
from tblMain m
) m
where seqnum = 1
To get an arbitrary row, you could use:
select sum(fldThree)
from (select m.*,
row_number() over (partition by fldOne order by (select NULL as noorder)) as seqnum
from tblMain m
) m
where seqnum = 1
Or, if FldTwo has the values in reverse order:
select sum(fldThree)
from (select m.*,
row_number() over (partition by fldOne order by FldTwo desc) as seqnum
from tblMain m
) m
where seqnum = 1
Maybe this?
SELECT SUM(fldThree) as ExpectedSum
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY fldOne ORDER BY fldTwo DSEC) Rn
FROM tblMain) as A
WHERE Rn = 1