MS ACCESS: How can i count distinct value using access query? - sql

here is the current complex query given below.
SELECT DISTINCT Evaluation.ETCode, Training.TTitle, Training.Tcomponent, Training.TImpliment_Partner, Training.TVenue, Training.TStartDate, Training.TEndDate, Evaluation.EDate, Answer.QCode, Answer.Answer, Count(Answer.Answer) AS [Count], Questions.SL, Questions.Question
FROM ((Evaluation INNER JOIN Training ON Evaluation.ETCode=Training.TCode) INNER JOIN Answer ON Evaluation.ECode=Answer.ECode) INNER JOIN Questions ON Answer.QCode=Questions.QCode
GROUP BY Evaluation.ETCode, Answer.QCode, Training.TTitle, Training.Tcomponent, Training.TImpliment_Partner, Training.Tvenue, Answer.Answer, Questions.Question, Training.TStartDate, Training.TEndDate, Evaluation.EDate, Questions.SL
ORDER BY Answer.QCode, Answer.Answer;
There is an another column Training.TCode. I need to count distinct Training.TCode, can anybody help me?
If you need more information please let me know

try
select ..., count(distinct Training.Tcode) as ..., ...
EDIT - please now look at this...
Take the following SQL code. The first select is how SQL server would do this and the second query should be access compliant...
declare #t table (eCode int, tcode int)
insert into #t values(1,1)
insert into #t values(1,1)
insert into #t values(1,2)
insert into #t values(1,3)
insert into #t values(2,2)
insert into #t values(2,3)
insert into #t values(3,1)
select
ecode, count(distinct tCode) countof
from
#t
group by
ecode
select ecode, count(*)
from
(select distinct tcode, ecode
from #t group by tcode, ecode) t
group by ecode
It returns the following:
ecode tcode
1 3 (there are 3 distinct tcode for ecode of 1)
2 2 (there are 2 distinct tcode for ecode of 2)
3 1 (there is 1 distinct tcode for ecode of 3)

I posted a similar question about a year ago in Google groups. I received an excellent answer:
A crosstab can do (from an original proposition from Steve Dassin) as long
as you count either the fund, either the subfund:
TRANSFORM COUNT(*) AS theCell
SELECT ValDate,
COUNT(*) AS StandardCount,
COUNT(theCell) AS DistinctCount
FROM tableName
GROUP BY ValDate
PIVOT fund IN(Null)
which, for each day (group), will return the number of records and the
number of different (distinct) funds.
Change
PIVOT fund IN(Null)
to
PIVOT subfund IN(Null)
to get the same, for sub-funds.
Hoping it may help,
Vanderghast, Access MVP
I don't know if that will work, but here's a link to that post.

Sadat, use a subquery like this:
SELECT DISTINCT Evaluation.ETCode, Training.TTitle, Training.Tcomponent, Training.TImpliment_Partner, Training.TVenue, Training.TStartDate, Training.TEndDate, Evaluation.EDate, Answer.QCode, Answer.Answer, Count(Answer.Answer) AS [Count], Questions.SL, Questions.Question,
(SELECT COUNT(*) FROM Training t2 WHERE t2.TCode = Evalution.ETCode) as TCodeCount
FROM ((Evaluation INNER JOIN Training ON Evaluation.ETCode=Training.TCode) INNER JOIN Answer ON Evaluation.ECode=Answer.ECode) INNER JOIN Questions ON Answer.QCode=Questions.QCode
GROUP BY Evaluation.ETCode, Answer.QCode, Training.TTitle, Training.Tcomponent, Training.TImpliment_Partner, Training.Tvenue, Answer.Answer, Questions.Question, Training.TStartDate, Training.TEndDate, Evaluation.EDate, Questions.SL
ORDER BY Answer.QCode, Answer.Answer;

I managed to do a count distinct value in Access by doing the following:
select Job,sum(pp) as number_distinct_fruits
from
(select Job, Fruit, 1 as pp
from Jobtable group by Job, Fruit) t
group by Job
You have to be careful as if there is a blank/null field (in my code fruit field) the group by will count that as a record. A Where clause in the inner select will ignore those though.
I've put this on my blog, but am concerned that I've discovered the answer too easily - others here seem to think that you need two sub queries to make this work. Is my solution viable?
Distinct groupings in Access

Have a look at this blog entry, it appears you can do this with subqueries....
http://blogs.msdn.com/access/archive/2007/09/19/writing-a-count-distinct-query-in-access.aspx

I would propose
select R_rep,sum(pp) as number_distinct_Billnos from (select R_rep, Billno, 1 as pp from `Vat_Sales` group by R_rep, Billno) t group by R_rep

try this:
SELECT DISTINCT e.ETCode, t.TTitle, t.Tcomponent,
t.TImpliment_Partner, t.TVenue, t.TStartDate,
t.TEndDate, e.EDate, a.QCode, a.Answer,
q.SL, q.Question,
Count(a.Answer) AnswerCount,
Min(Select Count(*)
From (Select Distinct TCode From Training) As Z ) TCodeCount
FROM Evaluation As e
JOIN Training AS t ON e.ETCode=t.TCode
JOIN Answer AS a ON e.ECode=a.ECode
JOIN Questions AS q ON a.QCode=q.QCode
GROUP BY e.ETCode, a.QCode, t.TTitle, t.Tcomponent,
t.TImpliment_Partner, t.Tvenue, a.Answer, q.Question,
t.TStartDate, t.TEndDate, Evaluation.EDate, q.SL
ORDER BY a.QCode, a.Answer;

Related

Building/Creating SQL Metrics from the table

I have a table:
SELECT aaa.sr_nbr,
aaa.inst_nbr,
bb.country,
bb.sr_control_type,
bb.it_tran_code,
ccc.cust_name,
ccc.cust_nbr
FROM tablea1 aaa
INNER JOIN tablea2 bb
ON aaa.inst_id=bb.inst_id AND aaa.item_id=bb.item_id
LEFT JOIN table3 ccc
ON bb.inst_id=ccc.inst_id AND bb.item_id=ccc.item_id
WHERE ccc.cust_name NOT LIKE '%EXP%'
AND ccc.cust_name NOT LIKE '%RMAA%' mt;
Now, I have created, separately, queries for metrics, like:
SELECT mt.sr_nbr,
mt.inst_nbr,
mt.country,
mt.sr_control_type,
mt.it_tran_code,
mt.cust_name,
mt.cust_nbr
COUNT(mt.sr_nbr) as cnt_nbr
FROM mt
WHERE mt.it_tran_code <> 'D'
GROUP BY 1,2,3,4,5,6,7;
or the another one:
SELECT t_2.sr_nbr,
t_2.inst_nbr,
t_2.country,
t_2.sr_control_type,
t_2.it_tran_code,
t_2.cust_name,
t_2.cust_nbr
SUM(t_2.sn_dup) AS sn_dup_sum
FROM (
SELECT
t_1.sr_nbr,
t_1.inst_nbr,
t_1.country,
t_1.sr_control_type,
t_1.it_tran_code,
t_1.cust_name,
t_1.cust_nbr
COUNT(t_1.sr_nbr) AS sn_dup
FROM
(
SELECT
mt.sr_nbr,
mt.inst_nbr,
mt.country,
mt.sr_control_type,
mt.it_tran_code,
mt.cust_name,
mt.cust_nbr
FROM mt
WHERE ccc.cust_name NOT LIKE '%EXP%'
AND ccc.cust_name NOT LIKE '%RMAA%'
) AS t_1
GROUP BY 1,2,3,4,5,6,7
HAVING
COUNT(t_1.sr_nbr) > 1
) AS t_2
GROUP BY 1,2,3,4,5,6,7;
and so on... I have about 10 similar metrics.
Now, I do not know the best way how to "put" those query metrics within the main table/query.
You can insert results of a SELECT query into a table if you are able to fill the INSERT statement correctly.
Example:
INSERT INTO Customers (CustomerName, City, Country)
SELECT SupplierName, City, Country FROM Suppliers
WHERE Country='Germany';
Source: https://www.w3schools.com/sql/sql_insert_into_select.asp
Make sure the amount and types of the results matches the columns you're trying to insert.

Query with different categories

I want to look if there are more than one QuestionCategory in one day in the table contentment. In my case people don't need to answer in one day questions with different categories. I can make a trigger of this.
The contentmenttable: employeeid, questionid, date, score
The questiontable: questionid, questioncat, question
Data contentmenttable: 1, 1, 11-18-2018, 4
Data questiontable: 1, Work, How is your job? 2, Work, Are you happy
with your job?
If have something like this:
select c.questionid, date
from contentment c
join question q
on c.questionid= q.questionid
group by c.questionid, date
having count(questioncat) >= 2
But this query is only counting IF a questionid is two times or more in this table, not if there are two different questioncategories in this table.
I use SQL Server.
So if someone wants to insert this:
insert into contentment values (1, 2, 11-18-2018', null) (null because employee needs to give a score)
The query needs to give this questionid and date (2 and 11-18-2018), because it is the same questioncat "work" on the same day 11-18-2018.
You need to add DISTINCT:
select c.questionid, date
from contentment c
join question q
on c.questionid= q.questionid
group by c.questionid, date
having count(DISTINCT questioncat) >= 2;
-- counting only different questioncat
Your question is hard to follow, but I think you want employees that have more than one question category in a given day. If so:
select c.employeeid, c.date, count(distinct q.questioncat)
from contentment c join
question q
on c.questionid = q.questionid
group by c.employeeid, c.date
having count(distinct q.questioncat) >= 2;

Select TOP predicate

I have a table with fields StudentID, ClassID, ExamID, SubjectID and Scores
I am trying to get a sum of 7 top Scores from attempted subjects from every student. The SQL statement below is giving me the sum of scores of all the subject from the top 7 students:
SELECT TOP 7 Sum(tblScores.Scores) AS Total, tblScores.AdmissionID
FROM tblScores
WHERE (((tblScores.ExamID)=[Forms]![frmReports]![lstC]) AND ((tblScores.ClassID)=[Forms]![frmReports]![lstB]))
GROUP BY tblScores.AdmissionID
ORDER BY Sum(tblScores.Scores) DESC;
The Class and Exam criteria is read from the Form "frmReports"
Any one who can help me out?
Consider a correlated subquery to calculate a running rank of scores. Then, nest this select query in a derived table for Score aggregation, filtered by each students' top 7 scores (including ties):
SELECT main.AdmissionID, Sum(main.Scores) As [Total]
FROM
(SELECT tblScores.AdmissionID, tblScores.Scores,
(SELECT Count(*) FROM tblScores sub
WHERE sub.AdmissionID = tblScores.AdmissionID
AND sub.Scores >= tblScores.Scores) As ScoreRank
FROM tblScores
WHERE (((tblScores.ExamID)=[Forms]![frmReports]![lstC])
AND ((tblScores.ClassID)=[Forms]![frmReports]![lstB]))
) As main
WHERE main.ScoreRank <= 7
GROUP BY main.AdmissionID
Try this:
SELECT TOP 7 Sum(tblScores.Scores) AS Total, tblScores.AdmissionID
FROM tblScores
HAVING (((tblScores.ExamID)=[Forms]![frmReports]![lstC]) AND ((tblScores.ClassID)=[Forms]![frmReports]![lstB]))
GROUP BY tblScores.AdmissionID
ORDER BY Sum(tblScores.Scores) DESC;
# Parfait - Thank you for your guidance. I have actually tweaked your solution to get a perfect answer: Here is the sql:
SELECT Dupe.AdmissionID, Dupe.Scores, Dupe.ScoreRank
FROM (SELECT qryFilteredScores.AdmissionID, qryFilteredScores.Scores, (SELECT Count(*) FROM qryFilteredScores AS sub
WHERE sub.AdmissionID = qryFilteredScores.AdmissionID AND sub.Scores >qryFilteredScores.Scores)+ 1 AS ScoreRank FROM qryFilteredScores WHERE (((qryFilteredScores.ExamID)=Forms!frmReports!lstC) And ((qryFilteredScores.ClassID)=Forms!frmReports!lstB))) AS Dupe
WHERE (((Dupe.Scores)<>0) AND ((Dupe.ScoreRank)<=7));
Alternatively, you can use a derived table or stored query (where you save derived table as separate object referenced in this query) and avoid inline subqueries:
SELECT Dupe.AdmissionID, Total.TotalScore
FROM qryFilteredScores AS Dupe
INNER JOIN
(SELECT sub.AdmissionID, Sum(sub.Scores) As TotalScore
FROM qryFilteredScores sub
WHERE ([AdmissionID]=Dupe.[AdmissionID]
AND ((sub.ClassID)=[Forms]![frmReports]![lstB])
AND ((tblScores.ExamID)=[Forms]![frmReports]![lstC]))
GROUP BY sub.AdmissionID) AS Total
ON Dupe.AdmissionID = Total.AdmissionID
GROUP BY Dupe.AdmissionID, Total.TotalScore
ORDER BY Dupe.AdmissionID;

Show unique ID's in a table with all extra info

SELECT Personeelsnummer, Achternaam, Voornaam, Departement, SubDep, SubSubDep, FTE, RedenUitDienst, Anciennitëitsdatum, GeldigOp, Schrapping, Ancienniteit, Positie, Nieveau, OmschrijfingStatuut
FROM tbl_Worker
GROUP BY Personeelsnummer
OR
SELECT (DISTINCT Personeelsnummer), Achternaam, Voornaam, Departement, SubDep, SubSubDep, FTE, RedenUitDienst, Anciennitëitsdatum, GeldigOp, Schrapping, Ancienniteit, Positie, Nieveau, OmschrijfingStatuut
FROM tbl_Worker
GROUP BY Personeelsnummer
I have a worker table with 49000 records, this includes a 'snapshot' from all workers EVERY month. But what I need is a table with all employees the company 'ever' had but only once. so I tried to wright the query's show above but they are not working.
So what I need is a query that shows all unique 'Personeelsnummers' with all the extra information about these persons.
what does work is this: SELECT DISTINCT Personeelsnummer FROM tbl_Worker ==> this gives me a table with 1200 records but only the numbers but I need all the extra information.
Instead of GROUP BY, use WHERE to get the first or last record:
SELECT w.*
FROM tbl_Worker as w
WHERE monthcol = (SELECT MAX(w2.monthcol)
FROM tbl_Worker as w2
WHERE w2.Personeelsnummer = w.Personeelsnummer
);
You would use MIN() to get the first month's record. My Dutch is a bit weak, so I don't know which column refers to the date for the record.
For performance, you want an index on tbl_Worker(Personeelsnummer, GeldigOp):
create index idx_tbl_worker_Personeelsnummer_GeldigOp on tbl_Worker(Personeelsnummer, GeldigOp);
EDIT:
Or you can do it with a JOIN:
SELECT w.*
FROM tbl_Worker as w INNER JOIN
(SELECT Personeelsnummer, MAX(GeldigOp) as max_GeldigOp
FROM tbl_Worker
GROUP BY Personeelsnummer
) as ww
ON ww.Personeelsnummer = w.Personeelsnummer and ww.max_GeldigOp = w.GeldigOp;
You're looking for a group by:
select *
from table
group by field1
Which can occasionally be written with a distinct on statement:
select distinct on field1 *
from table
As seen in this topic.

SQL: multiple counts from same table

I am having a real problem trying to get a query with the data I need. I have tried a few methods without success. I can get the data with 4 separate queries, just can't get hem into 1 query. All data comes from 1 table. I will list as much info as I can.
My data looks like this. I have a customerID and 3 columns that record who has worked on the record for that customer as well as the assigned acct manager
RecID_Customer___CreatedBy____LastUser____AcctMan
1-------1374----------Bob Jones--------Mary Willis------Bob Jones
2-------1375----------Mary Willis------Bob Jones--------Bob Jones
3-------1376----------Jay Scott--------Mary Willis-------Mary Willis
4-------1377----------Jay Scott--------Mary Willis------Jay Scott
5-------1378----------Bob Jones--------Jay Scott--------Jay Scott
I want the query to return the following data. See below for a description of how each is obtained.
Employee___Created__Modified__Mod Own__Created Own
Bob Jones--------2-----------1---------------1----------------1
Mary Willis------1-----------2---------------1----------------0
Jay Scott--------2-----------1---------------1----------------1
Created = Counts the number of records created by each Employee
Modified = Number of records where the Employee is listed as Last User
(except where they created the record)
Mod Own = Number of records for each where the LastUser = Acctman
(account manager)
Created Own = Number of Records created by the employee where they are
the account manager for that customer
I can get each of these from a query, just need to somehow combine them:
Select CreatedBy, COUNT(CreatedBy) as Created
FROM [dbo].[Cust_REc] GROUP By CreatedBy
Select LastUser, COUNT(LastUser) as Modified
FROM [dbo].[Cust_REc] Where LastUser != CreatedBy GROUP By LastUser
Select AcctMan, COUNT(AcctMan) as CreatePort
FROM [dbo].[Cust_REc] Where AcctMan = CreatedBy GROUP By AcctMan
Select AcctMan, COUNT(AcctMan) as ModPort
FROM [dbo].[Cust_REc] Where AcctMan = LastUser AND NOT AcctMan = CreatedBy GROUP By AcctMan
Can someone see a way to do this? I may have to join the table to itself, but my attempts have not given me the correct data.
The following will give you the results you're looking for.
select
e.employee,
create_count=(select count(*) from customers c where c.createdby=e.employee),
mod_count=(select count(*) from customers c where c.lastmodifiedby=e.employee),
create_own_count=(select count(*) from customers c where c.createdby=e.employee and c.acctman=e.employee),
mod_own_count=(select count(*) from customers c where c.lastmodifiedby=e.employee and c.acctman=e.employee)
from (
select employee=createdby from customers
union
select employee=lastmodifiedby from customers
union
select employee=acctman from customers
) e
Note: there are other approaches that are more efficient than this but potentially far more complex as well. Specifically, I would bet there is a master Employee table somewhere that would prevent you from having to do the inline view just to get the list of names.
this seems pretty straight forward. Try this:
select a.employee,b.created,c.modified ....
from (select distinct created_by from data) as a
inner join
(select created_by,count(*) as created from data group by created_by) as b
on a.employee = b.created_by)
inner join ....
This highly inefficient query may be a rough start to what you are looking for. Once you validate the data then there are things you can do to tidy it up and make it more efficient.
Also, I don't think you need the DISTINCT on the UNION part because the UNION will return DISTINCT values unless UNION ALL is specified.
SELECT
Employees.EmployeeID,
Created =(SELECT COUNT(*) FROM Cust_REc WHERE Cust_REc.CreatedBy=Employees.EmployeeID),
Mopdified =(SELECT COUNT(*) FROM Cust_REc WHERE Cust_REc.LastUser=Employees.EmployeeID AND Cust_REc.CreateBy<>Employees.EmployeeID),
ModOwn =
CASE WHEN NOT Empoyees.IsManager THEN NULL ELSE
(SELECT COUNT(*) FROM Cust_REc WHERE AcctMan=Employees.EmployeeID)
END,
CreatedOwn=(SELECT COUNT(*) FROM Cust_REc WHERE AcctMan=Employees.EmployeeID AND CReatedBy=Employees.EMployeeID)
FROM
(
SELECT
EmployeeID,
IsManager=CASE WHEN EXISTS(SELECT AcctMan FROM CustRec WHERE AcctMan=EmployeeID)
FROM
(
SELECT DISTINCT
EmployeeID
FROM
(
SELECT EmployeeID=CreatedBy FROM Cust_Rec
UNION
SELECT EmployeeID=LastUser FROM Cust_Rec
UNION
SELECT EmployeeID=AcctMan FROM Cust_Rec
)AS Z
)AS Y
)
AS Employees
I had the same issue with the Modified column. All the other columns worked okay. DCR example would work well with the join on an employees table if you have it.
SELECT CreatedBy AS [Employee],
COUNT(CreatedBy) AS [Created],
--Couldn't get modified to pull the right results
SUM(CASE WHEN LastUser = AcctMan THEN 1 ELSE 0 END) [Mod Own],
SUM(CASE WHEN CreatedBy = AcctMan THEN 1 ELSE 0 END) [Created Own]
FROM Cust_Rec
GROUP BY CreatedBy