Aggregate function / Group By - invalid column error - sql

Using classic ASP and MS-SQL server 2008
What I am trying to do is select duplicate records, and count them so I can then update the first one and delete the rest.
My query selects the duplicates OK but as soon as I try and introduce a count it stops working with the message "Column 'calendar.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
I have tried to rewrite this and added the count to the second SELECT and adding the id to GROUP BY (and as many combinations of this sort of thing as I can think of but I still get errors. The answers I have looked at on stackoverflow for a solution seem to be a little complicated and not really applicable (or I'm not looking for the right thing)
Where am I going wrong with this?
(also is this the best method to look for and edit duplicates in a smallish table (200k rows?)
Dim strSQL_dup, rsSQL_dup, SQL_dupRecords, RecCount
strSQL_dup = "SELECT id, COUNT(id) AS RecCount FROM calendar WHERE start_date IN ( SELECT start_date FROM calendar WHERE pId = '" & pId & "' GROUP BY start_date HAVING (COUNT(start_date ) > 1) ) "
Set rsSQL_dup = conn.Execute(strSQL_dup)
While Not rsSQL_dup.EOF
If RecCount = 1 Then
'will eventually update the row
response.write(rsSQL_dup("id")) ' id of first'
Else
'will eventually delete the other rows
response.write(rsSQL_dup("id")) ' id of subsiquet rows
End If
rsSQL_dup.MoveNext
Wend

It seems you are missing GROUP BY in the main query:
SELECT id, COUNT(id) AS RecCount
FROM calendar
WHERE start_date IN (SELECT start_date FROM calendar
WHERE pId = '" & pId & "'
GROUP BY start_date
HAVING (COUNT(start_date ) > 1) )
GROUP BY clalendar.id
(The last line can be of course GROUP BY id I just wanted to highlight the link between the last and first lines)

The issue is that COUNT is an aggregate function, so whatever argument you pass to it needs to be in your GROUP BY clause.
If id itself is your key to determine uniqueness, you can change your query to
SELECT id, COUNT(id) AS RecCount FROM calendar group by id having count(id) > 1
If the date matters for filtering a subset of your data e.g. to search in a particular period only, you can include it in a WHERE clause. On the other hand, if date and id together determine uniqueness, you will need to include both fields in your GROUP BY clause.

Related

Need to lookup part data when there are multiple rows of the same part

I have a SQL Table that has parts with their own 2D barcodes. There may be multiple rows of the same part. Each row has a column with the Date_Time stamp.
What I need is to get the latest part data and view one of the columns to see if that value is INT 1.
Example below: Look up the latest timestamp for part "5" and see if "PartStatusSt1" is '1'
enter image description here
enter image description here
Here is my query:
"select * from [AppsData].[dbo].[OilPumpCoverTest] where [2DMatrix] like '" & HMIRuntime.Tags("2DMatrix").Read(1) & "'"
Then I need to look at column name "PartStatusSt1" and move that INT value to a WinCC Tag as described below:
HMIRuntime.Tags("Sql_Station1_Status").Write
Recordset.Fields("PartStatusSt1").Value,1
The code above works but it grabs a random row of part data if I have multiple rows of the same part (via 2DMatrix). I need to grab the latest data per Date_Time stamp.
NOTE: My code is in WinCC via VBS.
Thanks for any help!
"select top 1 *
from [AppsData].[dbo].[OilPumpCoverTest]
where [2DMatrix] like '" & HMIRuntime.Tags("2DMatrix").Read(1) & "' order by Date_Time desc "
To get the latest part records, I'd start by using RANK to assign a number to each part based on its time stamp. For example, if part A has three time stamps, each record would be assigned rank 1, 2, and 3, depending on your sorting. I do something similar for the part numbers I work with. To get the latest records for parts, you can then query all where rankval = 1.
Small sample below...
SELECT z.*
FROM
(SELECT RANK() OVER(PARTITION BY PartNo, LotNumber ORDER BY DatePosted DESC) AS rankval , TagNo, PartNo, LotNumber, DatePosted FROM PartTable) AS z
--WHERE z.rankval = 1
You could then use a case statement or where clause to check for the part or part status.

Not contained in eaggregate function/ the GROUP BY AND max date does not show the latest date

I am stucked here and your help will be appreciated. Based on the code that you see below:
I have a sub query with some conditions. especifically, the following:
AND OwnedByTeamJ='C - O Review'
AND OwnedByTeamJ is null
I want to get the results from the subquery,
Do another select on them because all I want is the latest date listed the table. As you can see in the picture, I want to be able to extract row#3 which has the highest date and its own by the team which is null (I guess! since there is no value there).
Now the problems:
1-at first the code worked and I saw all the records! though, it didsn't pick the latest date
2- sudennly it stopped working and saw this error:
Column 'tt.IncidentID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
select
distinct max(LastModifiedDateTimeJ),
incidentID,
EffecRequestStatus,
OwnedByTeamJ
From (
select
EffecRequestStatus,
IncidentID,
LastModifiedDateTimeJ,
OwnedByTeamJ,
DetailsJ,
Status,
OwnedByTeam
from IncidentView
where
CAST(CreatedDateTime as DATE) >='05-01-2019'
AND JournalTypeName like '%Journal - Note%'
AND OwnedByTeamJ='C - O Review'
AND OwnedByTeamJ is null
group by
EffecRequestStatus,
IncidentID,
LastModifiedDateTimeJ,
OwnedByTeamJ,
DetailsJ,
Status,
OwnedByTeam
) as tt
where
tt. RequestStatus not in ('Submission','P-C submission','C Review')
A sample of data look like the following but my table has more columns than that is listed here:
1) These conditions should not coexist:
AND OwnedByTeamJ='C - O Review'
AND OwnedByTeamJ is null
...because these two things are never true at the same time, and you will get an empty result-set. I guess what you want is
AND (OwnedByTeamJ='C - O Review' or OwnedByTeamJ is null)
2) The error you mention does not seem to agree with the query you've shown us. Did you try to make another group by externally?
3) It doesn't make sense to use distinct together with any aggregation function like max,sum, count etc.
4) As long as you have included EffecRequestStatus within the group by, you will get 3 rows, not 1, because all 3 rows have a different value for EffecRequestStatus. You will have to remove it from the group by, and therefore from the select as well, if you only want to see one row.
Try this, if you want to have a not empty result:
AND (OwnedByTeamJ='C - O Review'
OR OwnedByTeamJ is null)

VBA Access Query for Day Summary

I use this forum all the time for VBA help but this is the first time I have to post something myself.
I am trying to make a report that provides a summary of various alarms stored in Access. I want to provide a simple Count of each alarm, each day. I have used some SQL queries but not really any Access. I took the fact that Access can do Pivot tables from Access itself. If there is a better way, please let me know.
Set CommandQuery.activeConnection = conn
commandQuery.CommandText = _
"TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast " & _
"SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc " & _
"FROM FixAlarms " & _
"WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime " & _
"GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr " & _
"PIVOT Format([Alm_NativeTimeIn],""Short Date"")"
rec.Open commandQuery
This is the code I am using. I had to retype it, so please forgive any typo. It does most of what I want but it does not give me any indication of what day each column is. I need a header on each column in case there were no alarms one day. I think the answer lies within the IN part of the PIVOT but I can't get it to work without syntax errors. I thought all I had to do was add on
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN 01/20/15"
Please help if you can.
Thanks.
In order to get the records for all day, even those where there were no activity you need to create these days. The simplest way to do so in access is to use a set of UNION statements to create a fake table for the days similar to this:
SELECT #2015-01-20# as dt FROM dual
UNION ALL
SELECT #2015-01-21# as dt FROM dual
UNION ALL
SELECT #2015-01-22# as dt FROM dual
If you try the above query in Access it will not work, as there is no table called dual. You will have to create it. Check this SO question.
After you created the above query you can LEFT JOIN it with the source table.
TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast
SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc
FROM
(SELECT #2015-01-20# as dt FROM dual
UNION ALL
SELECT #2015-01-21# as dt FROM dual
UNION ALL
SELECT #2015-01-22# as dt FROM dual) as dates LEFT JOIN
FixAlarms ON DateValue(FixAlarms.[Alm_NativeTimeIn]) = dates.dt
WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime
GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr
PIVOT Format(dates.dt, 'Short Date')
EDIT: I must add that this is not the only way of achieving it. Another way is to use a Numbers table. Create a table called Numbers with a single numeric column n and fill it with numbers 0 to 100 (depends on the maximum number of days you wish to include into your query). Then your query for the dates will be:
SELECT DateAdd('d', n, #2015-01-20#) as dt FROM numbers where n < 30;
And the resulting query will be:
TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast
SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc
FROM
(SELECT DateAdd('d', n, #2015-01-20#) as dt FROM numbers where n < 30) as dates LEFT JOIN
FixAlarms ON DateValue(FixAlarms.[Alm_NativeTimeIn]) = dates.dt
WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime
GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr
PIVOT Format(dates.dt, 'Short Date')
When using PIVOT columnName IN (ValueList) ValueList is
In parentheses
In quotes
Comma separated
So you're
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN 01/20/15"
Needs to become
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN (""01/20/15"")
With that said, this will not filter your records using PIVOTS in IN statement. You need to use the WHERE clause still.
If the end goal is to represent your data left to right then this will work. It will be a lot of extra work to make this work as a report though because your controls will not be bound to predictable columns. The Column names will change for different parameters.
You could leave this as a traditional query (not pivoted) and have a much easier time reporting it. If you are showing users the grid directly or exporting to Excel then this is not a problem.
So, I just wanted to add a header to my pivot table that would tell me what date the particular column was for.
The part of the code that I did not show was that I was using a rec.getrows to move all of my data into a simpler array variable. While this had all the data from Access, it did not have any headers to inform me what was a tagname, what was a description, and what was which date.
I found that in the recordset itself under fields.item(n) there was a Name attribute. This name told me where the column data came from or the date of the data. Using this and a simple day(date) function, I was able to make my monthly report summarizing all of the alarms.
Thanks for your help guys, but I either was not clear in my description of the problem or it was being over thought.

Getting a unique value from an aggregated result set

I've got an aggregated query that checks if I have more than one record matching certain conditions.
SELECT RegardingObjectId, COUNT(*) FROM [CRM_MSCRM].[dbo].[AsyncOperationBase] a
where WorkflowActivationId IN ('55D9A3CF-4BB7-E311-B56B-0050569512FE',
'1BF5B3B9-0CAE-E211-AEB5-0050569512FE',
'EB231B79-84A4-E211-97E9-0050569512FE',
'F0DDF5AE-83A3-E211-97E9-0050569512FE',
'9C34F416-F99A-464E-8309-D3B56686FE58')
and StatusCode = 10
group by RegardingObjectId
having COUNT(*) > 1
That's nice, but then there is one field in AsyncOperationBase that will be unique. Say count(*) = 3, well, AsyncOperationBaseId in AsyncOperationBase will have 3 different values since AsyncOperationBase is the table's primary key.
To be honest, I would not even know what terms and expressions to Google to find a solution.
If anyone has a solution and also, is there any words to describe what I'm looking for ? Perhaps BI people are often faced with such a requirement or something...
I could do it with an SSRS report where the report would visually do the grouping then I could expand each grouped row to get the AsyncOperationBaseId value, but simply through SQL, I can't seem to find a way out...
Thanks.
select * from [CRM_MSCRM].[dbo].[AsyncOperationBase]
where RegardingObjectId in
(
SELECT RegardingObjectId
FROM [CRM_MSCRM].[dbo].[AsyncOperationBase] a
where WorkflowActivationId IN
(
'55D9A3CF-4BB7-E311-B56B-0050569512FE',
'1BF5B3B9-0CAE-E211-AEB5-0050569512FE',
'EB231B79-84A4-E211-97E9-0050569512FE',
'F0DDF5AE-83A3-E211-97E9-0050569512FE',
'9C34F416-F99A-464E-8309-D3B56686FE58'
)
and StatusCode = 10
group by RegardingObjectId
having COUNT(*) > 1
)

Oracle Group by issue

I have the below query. The problem is the last column productdesc is returning two records and the query fails because of distinct. Now i need to add one more column in where clause of the select query so that it returns one record. The issue is that the column i need
to add should not be a part of group by clause.
SELECT product_billing_id,
billing_ele,
SUM(round(summary_net_amt_excl_gst/100)) gross,
(SELECT DISTINCT description
FROM RES.tariff_nt
WHERE product_billing_id = aa.product_billing_id
AND billing_ele = aa.billing_ele) productdescr
FROM bil.bill_sum aa
WHERE file_id = 38613 --1=1
AND line_type = 'D'
AND (product_billing_id, billing_ele) IN (SELECT DISTINCT
product_billing_id,
billing_ele
FROM bil.bill_l2 )
AND trans_type_desc <> 'Change'
GROUP BY product_billing_id, billing_ele
I want to modify the select statement to the below way by adding a new filter to the where clause so that it returns one record .
(SELECT DISTINCT description
FROM RRES.tariff_nt
WHERE product_billing_id = aa.product_billing_id
AND billing_ele = aa.billing_ele
AND (rate_structure_start_date <= TO_DATE(aa.p_effective_date,'yyyymmdd')
AND rate_structure_end_date > TO_DATE(aa.p_effective_date,'yyyymmdd'))
) productdescr
The aa.p_effective_date should not be a part of GROUP BY clause. How can I do it? Oracle is the Database.
So there are multiple RES.tariff records for a given product_billing_id/billing_ele, differentiated by the start/end dates
You want the description for the record that encompasses the 'p_effective_date' from bil.bill_sum. The kicker is that you can't (or don't want to) include that in the group by. That suggests you've got multiple rows in bil.bill_sum with different effective dates.
The issue is what do you want to happen if you are summarising up those multiple rows with different dates. Which of those dates do you want to use as the one to get the description.
If it doesn't matter, simply use MIN(aa.p_effective_date), or MAX.
Have you looked into the Oracle analytical functions. This is good link Analytical Functions by Example