I tried to show staff name, purchase date and count of transactions.
Below is my code; and I get this error:
Msg 147, Level 15, State 1, Line 260
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Code:
select
mt.StaffName,
mp.PurchaseDate,
[TotalTransaction] = count(mp.PurchaseID)
from
MsStaff mt
join
MsPurchase mp on mt.staffid = mp.staffid
where
mt.staffname like '%o%'
and count(mp.PurchaseID) > 1
You need to use GBH — GROUP BY and HAVING clauses.
SELECT mt.StaffName,
mp.PurchaseDate,
[TotalTransaction] = COUNT(mp.PurchaseID)
FROM MsStaff mt JOIN MsPurchase mp ON mt.staffid = mp.staffid
WHERE mt.staffname LIKE '%o%'
GROUP BY mt.StaffName, mp.PurchaseDate
HAVING COUNT(mp.PurchaseID) > 1
Note that COUNT(mp.PurchaseID) only counts the non-NULL values in the mp.PurchaseID column. It is slower than COUNT(*) unless the optimizer can determine that there are no NULL values in mp.PurchaseID.
Related
I need to add a column with the content of this query :
SELECT COUNT(*) FROM account_subscriptiongroups WHERE account_subscriptiongroups.active = true AND account_subscriptiongroups.user_id = account_user.id
to this query :
SELECT
account_user.id as user_id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id as sub_group_id,
account_adminaction.description,
account_adminaction.id as admin_action_id,
account_adminaction.created_on as subscription_ended_on
FROM
account_adminaction
LEFT JOIN
account_user ON account_user.id = account_adminaction.user_id
LEFT JOIN
account_subscriptiongroup ON account_adminaction.sub_group_id = account_subscriptiongroup.id
WHERE
account_adminaction.created_on >= '2021-04-07' AND account_adminaction.created_on <= '2021-04-13' AND
((account_adminaction.description LIKE 'Arrêt de l''abonnement%') OR (account_adminaction.description LIKE 'L''utilisateur a arrêté%'))
ORDER BY
subscription_ended_on
I tried adding a LEFT JOIN like that:
LEFT JOIN
account_subscriptiongroup all_sg ON account_user.id = account_subscriptiongroup.user_id
with this line in my WHERE statement :
AND all_sg.active = true
and this line in my SELECT :
COUNT(all_sg.id)
but I get an error :
ERROR: column "account_user.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 2: account_user.id as user_id, account_user.email, account_us...
^
I don't understand how I could perform this action properly
To count something, you need to specify a group where that count applies.
So every column that you select (and is not used in an aggregate function, like COUNT or SUM), you need to mention in the GROUP BY clause.
Or to put it the other way around: the non-aggregate columns must apply to all rows that are contained in that particular COUNT.
So between the WHERE and ORDER BY clauses, add a GROUP BY clause:
GROUP BY account_user.id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id,
account_adminaction.description,
account_adminaction.id,
account_adminaction.created_on
If, on the other hand, you want a count from a different table, you can add a sub-select:
SELECT
account_user.id as user_id, account_user.email, account_user.first_name, account_user.last_name, account_user.phone,
account_subscriptiongroup.id as sub_group_id,
account_adminaction.description,
account_adminaction.id as admin_action_id,
account_adminaction.created_on as subscription_ended_on,
(SELECT COUNT(*)
FROM account_subscriptiongroups
WHERE account_subscriptiongroups.active = true
AND account_subscriptiongroups.user_id = account_user.id) AS groupcount
FROM
account_adminaction
LEFT JOIN
account_user ON account_user.id = account_adminaction.user_id
You can left join to to a derived table that does the grouping and counting:
SELECT au.id as user_id, au.email, au.first_name, au.last_name, au.phone,
asg.id as sub_group_id,
ad.description,
ad.id as admin_action_id,
ad.created_on as subscription_ended_on,
asgc.num_groups
FROM account_adminaction ad
LEFT JOIN account_user au ON au.id = ad.user_id
LEFT JOIN account_subscriptiongroups asg on ON ad.sub_group_id = asg.id
LEFT JOIN (
SELECT user_id, count(*) as num_groups
FROM account_subscriptiongroups ag
WHERE ag.active
GROUP by user_id
) asgc on asgc.user_id = au.id
WHERE ad.created_on >= '2021-04-07'
AND ad.created_on <= '2021-04-13'
AND ((ad.description LIKE 'Arrêt de l''abonnement%') OR (ad.description LIKE 'L''utilisateur a arrêté%'))
ORDER BY subscription_ended_on
It's not entirely clear to me, what you are trying to count, but another option (most probably slower) could be to use a window function combined with a filter clause:
count(*) filter (where asg.active) over (partition by asg.user_id) as num_groups
EDIT: my answer is the same as submitted by a_horse_with_no_name
Two answers, a literal one just solving the problem you posed, and then another one questioning whether what you asked for is really what you want.
Simple answer: modify your desired query to add user_id to the Select and remove user_id from the Where clause. Now you have a table that can be left-joined to the rest of your larger query.
...
Left Join (Select user_id, count(*) as total_count
From account_subscriptiongroup
Where account_subscriptiongroups.active = true
Group By user_id) Z
On Z.user_id=account_user.id
I question whether this count is what you really want here. This counts every account_subscriptiongroup entry for all time but only the active ones. Your larger query brings back inactive as well as active records, so if your goal is to create a denominator for a percentage, you are mixing 'apples and oranges' here.
If you decide you want a total by user of the records in your query instead, then you can add one more element to your larger query without adding any more tables. Use a windowing function like this:
Select ..., Sum(Case When account_subscriptiongroup.active Then 1 else 0 End) Over (Group By account_user.id) as total count
This just counts the records within the date range and having the desired actions.
Here is my query and I want to add the "count of SalID group by OFID" and store the result in the same table.
SELECT
T_OF.OFID,
T_OF.OFDateDPrev, T_OF.OFDateFPrev,
T_OF_User.OFUserID,
T_OF_User.SalID
INTO T_tracing
FROM T_OF
INNER JOIN T_OF_User
ON T_OF_User.OFID = T_OF.OFID
I tried this:
SELECT
T_OF.OFID,
T_OF.OFDateDPrev, T_OF.OFDateFPrev,
T_OF_User.OFUserID,
Count (SalID) FROM T_OF_User GROUP BY OFID
INTO T_tracing
FROM T_OF
INNER JOIN T_OF_User
ON T_OF_User.OFID = T_OF.OFID
But I have an error message. Any help please?
I think you want a window function:
SELECT T_OF.OFID, T_OF.OFDateDPrev, T_OF.OFDateFPrev, T_OF_User.OFUserID,
Count(SalID) OVER (PARTITION BY T_OF.OFID) as cnt
INTO T_tracing
FROM T_OF JOIN
T_OF_User
ON T_OF_User.OFID = T_OF.OFID;
You also need to give the result of the expression a name for T_Tracing.
I have a very generic query that is grouping by the ID and summing up the volume and the getting the maximum address no. When I run it I get the following record count:
SELECT (case when m.participant_id=0 then 100000000 + m.member_id else m.participant_id END) as PID,
max(m.address_no) as address_no, sum(e.volume) as P3M_Vol into dbo.tmp_MC_P3M_FuelsPromo_3
from dbo.MonthlyDataMart e
inner join dbo.v_sr_member m on e.member_id = m.member_id
where e.member_type_cd = 'MC'
and e.year = 2014 and e.month between 2 and 4
and e.tran_code in ('PTSEARN','PREMIUM')
and not exists (select 1 from dbo.v_DNC d where e.member_id = d.member_id)
group by (case when m.participant_id=0 then 100000000 + m.member_id else m.participant_id END)
And I get the following Message:
Warning: Null value is eliminated by an aggregate or other SET operation.
(16828 row(s) affected)
I then removed the sum(e.volume) column in the query (the following code:)
SELECT (case when m.participant_id=0 then 100000000 + m.member_id else m.participant_id END) as PID,
max(m.address_no) as address_no into dbo.tmp_MC_P3M_FuelsPromo_2
from dbo.MonthlyDataMart e
inner join dbo.v_sr_member m on e.member_id = m.member_id
where e.member_type_cd = 'MC'
and e.year = 2014 and e.month between 2 and 4
and e.tran_code in ('PTSEARN','PREMIUM')
and not exists (select 1 from dbo.v_DNC d where e.member_id = d.member_id)
group by (case when m.participant_id=0 then 100000000 + m.member_id else m.participant_id END)
And I get different number of rows!
Warning: Null value is eliminated by an aggregate or other SET operation.
(34023 row(s) affected)
Any idea why this happens? I only removed the aggregate function and the row count are not the same. I am using MS SQL 2000.
Max () and sum () functions are eliminating nulls in this query.
Error is for that columns inside these functions.
The row affected change is for not having sum () inside group by aggrigate functions.
Good luck
Use ISNULL in the value you are aggregating. Take a good look what exact behavior you want in the query!
The reason your error rows are different is that you are grouping, aggregating and inner joining on potential NULLS. Depending on where records get skipped because of this you can get wildly variable results.
I have the following query that works fine:
SELECT NomComplet, IIF(Count(FS3.Index) = 0, '0 (RAS)', Count(FS3.Index))
FROM ControleAcces INNER JOIN (
Employes LEFT JOIN (
SELECT FS1.Index, FS1.OTP, FS1.OTP, FS1.Axe, FS1.FaitSaillant, FS1.Utilisateur, FS2.DateInsertion
FROM FaitsSaillants AS FS1 INNER JOIN (
SELECT Axe, Index, Max(FaitsSaillants.DateInsertion) AS DateInsertion
FROM FaitsSaillants
WHERE DateValue(DateInsertion) > #2010-01-01#
AND DateValue(DateInsertion) < #2011-12-31#
GROUP BY Axe, Index
) AS FS2
ON (FS1.DateInsertion = FS2.DateInsertion
AND FS1.Index = FS2.Index)
WHERE FS1.Axe = 'Project' AND FS2.Axe = 'Project'
) AS FS3
ON Employes.CIP = FS3.Utilisateur
)
ON ControleAcces.Valeur = Employes.CIP
GROUP BY NomComplet
ORDER BY NomComplet
Don't bother to fully understand it, all I want it to edit my IIF condition on the first line. Actually, the condition doesn't do much, it checks how many FS3.Index the query returns and concatenate (RAS) if it's 0. However, in fact, I would like it to check if there is any row in FaitsSaillants where Axe = 'RAS'. If the Count() of this is > 0, then the condition is met.
Can I do a subquery into the IIF segment, something like SELECT COUNT(Index) FROM FaitsSaillants WHERE Axe = 'RAS' AND Utilisateur = FS1.Utilisateur? If the result is 0, then I add the RAS to my second field's results. If not, it stays Count(FS3.Index).
I tried it and while the syntax is correct, the problem is it can't check for the Utilisateur = FS1.Utilisateur condition because FS1 is in the main query. However, I must check this because this is the only way to be sure that I'm looking for the right thing: it must be the same Utilisateur whether I'm in the main query or the subquery.
EDIT:
Here is a shorter version of what I tried from the answers/comments below.
SELECT NomComplet, IIf(FS2.AxeCount > 0, "0 (RAS)", count(FS3.index))
FROM ControleAcces INNER JOIN (Employes LEFT JOIN (SELECT FS2.AxeCount, FS1.Index, FS1.OTP, FS1.OTP, FS1.Axe, FS1.FaitSaillant, FS1.Utilisateur, FS2.DateInsertion
FROM FaitsSaillants AS FS1 INNER JOIN (
SELECT Axe, Index, Max(FaitsSaillants.DateInsertion) AS DateInsertion, SUM(IIf(Axe = 'RAS', 1, 0)) As AxeCount
FROM FaitsSaillants
GROUP BY Axe, Index
) AS FS2
ON (FS1.DateInsertion = FS2.DateInsertion
AND FS1.Index = FS2.Index)
) AS FS3 ON Employes.CIP = FS3.Utilisateur) ON ControleAcces.Valeur = Employes.CIP
GROUP BY NomComplet;
I still got an error about FS2.AxeCount that isn't a part of the aggregate function (iff).
I've also tried this:
SELECT NomComplet, IIf((select count(*) from FaitsSaillants where axe='RAS' and Utilisateur=ControleAcces.Valeur) > 0, "0 (RAS)", count(FS3.index))
FROM ControleAcces INNER JOIN (Employes LEFT JOIN (SELECT FS2.AxeCount, FS1.Index, FS1.OTP, FS1.OTP, FS1.Axe, FS1.FaitSaillant, FS1.Utilisateur, FS2.DateInsertion
FROM FaitsSaillants AS FS1 INNER JOIN (
SELECT Axe, Index, Max(FaitsSaillants.DateInsertion) AS DateInsertion, SUM(IIf(Axe = 'RAS', 1, 0)) As AxeCount
FROM FaitsSaillants
GROUP BY Axe, Index
) AS FS2
ON (FS1.DateInsertion = FS2.DateInsertion
AND FS1.Index = FS2.Index)
) AS FS3 ON Employes.CIP = FS3.Utilisateur) ON ControleAcces.Valeur = Employes.CIP
GROUP BY NomComplet, ControleAccess.Valeur;
FS3.Index is NULL if there is no corresponding record, because of the LEFT JOIN. Wouldn't a test
IIf(IsNull(FS3.Index), ..., ...)
... be sufficient? I'm not sure so, since other conditions and joins are involved as well.
UPDATE (recaptulation of comments)
We can get the desired count (AxeCount) from the innermost nested SELECT (FS2):
SELECT
Axe, Index, Max(FaitsSaillants.DateInsertion) AS DateInsertion,
SUM(IIf(Axe = 'RAS', 1, 0)) As AxeCount
FROM FaitsSaillants
...
This intermediate result must be passed to the outermost SELECT by including it in the select list of the intermediate SELECT (FS3):
SELECT FS2.AxeCount, FS1.Index, ...
The outer most SELECT has a GROUP BY clause. In this case, all fields of the select list must either be included in the GROUP BY clause or must be included in an aggregate function. The GROUP BY clause groups rows by the fields listed in this very clause. This usually reduces the number of rows, as several rows similar in their group fields are condensed to form one row. This means that the values of the remaining fields of the select list (not in the group fields) must be combined together. This is what the aggregate function does. Aggregate functions are
Avg (average)
Count
First, Last
Min, Max (minimum, maximum)
StDev, StDevP (standard deviation)
Sum
Var, VarP (variance)
See SQL Aggregate Functions (Access)
Now, we can add this in the outermost select list
IIf(SUM(FS2.AxeCount) > 0, ..., ...)
I'm a little unclear on exactly what you want to check in the FaitsSaillants table; you said:
I would like it to check if there is any row in FaitsSaillants where
Axe = 'RAS'. If the Count() of this is > 0, then the condition is met.
But you also stated:
something like SELECT COUNT(Index) FROM FaitsSaillants WHERE Axe =
'RAS' AND Employes.CIP = FS3.Utilisateur
My guess is that you meant SELECT COUNT(Index) FROM FaitsSaillants WHERE Axe = 'RAS', because in the second SQL statement you're joining to two tables that aren't being referenced in the FROM clause of your subquery.
What about using DCount in your IIF statement?
IIF(DCount("Index", "FaitsSaillants", "Axe='RAS'"), '0 (RAS)', Count(FS3.Index))
This should work if you meant SELECT COUNT(Index) FROM FaitsSaillants WHERE Axe = 'RAS', but it would need to be modified if you had something else in mind.
Just a caveat though: I would try to use the "domain" functions (DCount, DLookup, etc...) sparingly, because they are slow.
By the way, I believe you can also use a subquery in your IIF statement (is it giving you an error? It seems to work for me):
IIF((SELECT COUNT(*) FROM FaitsSaillants WHERE Axe = 'RAS'), '0 (RAS)', Count(FS3.Index))
Just make sure you are putting the subquery in parenthesis.
I'm trying to add all the values in a column to get the total of that column, anyone know the trick to this?
Here's my query:
select T.*,
sum(nvl(BIN1,0))+sum(nvl(BIN2,0))+sum(nvl((BIN3,0)) as TOTAL
from
(
SELECT CSM_FLASKS.FLASK_CODE,
MN_ASSAYS_STAGES.ASSAY_STAGE_ID,
VITRO_REP.TREATMENT_DOSE(CSM_FLASKS.GROUP_ID) AS TREATMENT_DOSE,
MN_RI_REP.FLASK_BIN_VALUE_BY_INDEX(MN_ASSAYS_STAGES.ASSAY_STAGE_ID, CSM_FLASKS.FLASK_ID, 1) AS BIN1,
MN_RI_REP.FLASK_BIN_VALUE_BY_INDEX(MN_ASSAYS_STAGES.ASSAY_STAGE_ID, CSM_FLASKS.FLASK_ID, 2) AS BIN2,
MN_RI_REP.FLASK_BIN_VALUE_BY_INDEX(MN_ASSAYS_STAGES.ASSAY_STAGE_ID, CSM_FLASKS.FLASK_ID, 3) AS BIN3,
MN_RI_REP.CBPI_FLASK(MN_ASSAYS_STAGES.ASSAY_STAGE_ID, CSM_FLASKS.FLASK_ID, 1, 2, 2) AS CBPI,
CSM_EXPERIMENTS.EXPT_CODE
FROM CSM_TREATMENT_GROUPS_EXPTS
INNER JOIN CSM_ASSAYS
ON CSM_ASSAYS.EXPT_ID = CSM_TREATMENT_GROUPS_EXPTS.EXPERIMENT_ID
INNER JOIN CSM_FLASKS
ON CSM_TREATMENT_GROUPS_EXPTS.GROUP_ID = CSM_FLASKS.GROUP_ID
INNER JOIN MN_ASSAYS
ON CSM_ASSAYS.ASSAY_ID = MN_ASSAYS.ASSAY_ID
INNER JOIN MN_ASSAYS_STAGES
ON MN_ASSAYS.MN_ASSAY_ID = MN_ASSAYS_STAGES.MN_ASSAY_ID
INNER JOIN CSM_EXPERIMENTS
ON CSM_EXPERIMENTS.EXPT_ID = CSM_TREATMENT_GROUPS_EXPTS.EXPERIMENT_ID
AND CSM_EXPERIMENTS.EXPT_ID = CSM_ASSAYS.EXPT_ID
WHERE CSM_ASSAYS.ASSAY_ID = 1000060
AND MN_ASSAYS_STAGES.STAGE_ID = 2
ORDER BY CSM_TREATMENT_GROUPS_EXPTS.ORDER_INDEX,
CSM_FLASKS.FLASK_ID,
CSM_FLASKS.IS_PLUS DESC
) T
Error:
ORA-00937: not a single-group group function
00937. 00000 - "not a single-group group function"
*Cause:
*Action:
Error at Line: 1 Column: 9
When using any aggregate function, you will need to add the non aggregated fields into a GROUP BY clause. So in your column you need to list those fields that are not listed in the aggregate function SUM in the GROUP BY clause. Therefore your query should be as following:
SELECT FLASK_CODE,
SUM(nvl(BIN1, 0)) + SUM(nvl(BIN2, 0)) + SUM(nvl((BIN3, 0)) AS TOTAL
FROM
(
...
) T
GROUP BY FLASK_CODE
This is just an example. But you have to determine what fields to select in the SELECT clause and needs to be listed too in GROUP BY clause.
Try This:
If You add all Data in single column means:
select sum( column_name ) from table inner join .........;
Finally you find the total