I have a problem with the following query:
WITH CTE_1 (stu_id
,meet_doc_id
,doc_name
,stu_name
,dob
,done
,date_meet_doc)
AS
(SELECT stu_id
,meet_doc_id
,doc_name
,stu_name
,dob
,CASE
WHEN (PATINDEX('%SMOKING%',act.VALUE)) THEN
'LMDO'
WHEN (PATINDEX('%NOT SMOKING%',act.VALUE)) THEN
'LMD1'
WHEN (ISNULL(CAST(act.VALUE as varchar(max)),'')='') THEN
'CLEAR'
ELSE
'CLEAR'
END done
,date_meet_doc
FROM
abc INNER JOIN
INNER JOIN
INNER JOIN
WHERE multiple conditions
)
SELECT * FROM CTE_1 one
WHERE date =(SELECT MAX(DATE) FROM CTE_1 two WHERE two.stu_id=one.stu_id
AND one.doc_name=two.doc_name)
ORDER BY stu_name,dob
;
The result set of the inner query(CTE_1) for three student(for eg) will be something like
stu_id meet_doc_id doc_name stu_name dob value date
101 0104 AD AM 15/06/1950 LMDO 2011-02-15
101 0105 AD AM 15/06/1950 CLEAR 2011-02-18
101 0106 AD AM 15/06/1950 CLEAR 2011-02-25
102 0107 AD AK 12/08/1987 CLEAR 2011-03-28
102 0108 AD AK 12/08/1987 LDMO 2011-04-29
103 0109 PK LMP 13/07/1970 CLEAR 2011-03-28
103 0110 PK LMP 13/07/1970 CLEAR 2011-05-12
AND when i execute the whole query my result set will be
stu_id meet_doc_id doc_name stu_name dob value date
101 0106 AD AM 15/06/1950 CLEAR 2011-02-25
102 0108 AD AK 12/19/1987 LDMO 2011-04-29
103 0110 PK LMP 13/07/1970 CLEAR 2011-05-12
What do i have to do to change the outer query to select only those value ie LDMO or LMD1 for a particular student and whose doctor is same?
Suppose if the student meets the doc multiple times and if in any of the cases if the student gets a LMDO or LMD1 then it should pick only that record irrespective of the date.
I am expecting my resultset to be something like:
stu_id meet_doc_id doc_name stu_name dob value date
101 0104 AD AM 15/06/1950 LMDO 2011-02-15
102 0107 AD AK 12/08/1987 CLEAR 2011-03-28
103 0110 PK LMP 13/07/1970 CLEAR 2011-05-12
The logic behind it is if the stu_id is same and the doc_name is same and if there exists a value either LMDO or LMD1 then show that record if not show the record which has CLEAR.
Simply i want to remove the MAX(date) and place a condition for the whole reporting period of that particular stu_id with the same doc_name.
Edit: To add a high-level description of what I did.
You want to get your original information (CTE_1) filtered down by 2 possible criteria. The easiest way to do this is to first establish those criteria in their own result sets. So, we have a subquery that returns a list of (Student, Doc, Max(Date)) combinations and a similar list that is filtered on the LMDO/LMD1 values.
Now, we need to LEFT JOIN to the filtered data since there may not be results for each student.
So now you have a list of Student/Doc/MaxDate and also a possible FilteredDate.
The final step is to JOIN that result set to the original data (CTE_1). Since the FilteredDate takes precedence, we check for that first through the ISNULL function and, if it isn't present, we use the MaxDate instead.
First, I'd change the original query to the following as I think you'll see some performance gains on large data-sets by eliminating the correlated subquery:
SELECT *
FROM CTE_1 one
INNER JOIN
(SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1 group by stu_id,doc_name) two
ON one.stu_id = two.stu_id and one.doc_name = two.doc_name
ORDER BY stu_name,dob
Now, we can add an additional, similar, join to get the max(date) where the Value is in your desired list. We'll need to shuffle the joins around a little bit too.
SELECT realdata.*
FROM
((SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1 group by stu_id,doc_name) maxdt
LEFT JOIN
(SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1
WHERE value in ('LMDO', 'LMD1')
group by stu_id,doc_name) filtered
ON maxdt.stu_id = filtered.stu_id and maxdt.doc_name = filtered.doc_name)
INNER JOIN CTE_1 realdata
ON realdata.stu_id = maxdt.stu_id and realdata.doc_name = maxdt.doc_name
and realdata.date = isnull(filtered.maxdate, maxdt.maxdate)
ORDER BY realdata.stu_name,realdata.dob
declare #TestTable
as table
(stu_id int,
meet_doc_id char(4),
doc_name char(2),
stu_name varchar(3),
dob date,
value varchar(5),
date_meet_doc date)
insert into #TestTable
(stu_id,meet_doc_id,doc_name,stu_name,dob,value,date_meet_doc)
values
(101,'0104','AD','AM', '19500615','LDMO' ,'2011-02-15'),
(101,'0105','AD','AM', '19500615','CLEAR','2011-02-18'),
(101,'0106','AD','AM', '19500615','CLEAR','2011-02-25'),
(102,'0107','AD','AK', '19870812','CLEAR','2011-03-28'),
(102,'0108','AD','AK', '19870812','LDMO' ,'2011-04-29'),
(103,'0109','PK','LMP','19700713','CLEAR','2011-03-28'),
(103,'0110','PK','LMP','19700713','CLEAR','2011-05-12');
WITH CTE_1 (stu_id
,meet_doc_id
,doc_name
,stu_name
,dob
,done
,date_meet_doc)
AS
(SELECT stu_id
,meet_doc_id
,doc_name
,stu_name
,dob
,value
,date_meet_doc
FROM #TestTable
),
CTE_2 as(
SELECT *,row_number() over (partition by stu_id order by case when done in ('LDMO','LDM1') then 0 else 1 end, date_meet_doc desc) rn FROM CTE_1)
select stu_id
,meet_doc_id
,doc_name
,stu_name
,dob
,value
,date_meet_doc
from CTE_2 where rn=1
;
Thanks to those who tried to understand but gave up since i couldnt explain it.
Thanks Again guys :)
Related
I have the following table that registers the days students went to school. I need to count the days they are PRESENT, but also need to count the total of school days for each month. (When ASISTENCIA is either 0 or 1)
This what I have so far, but it doesn't count the total.
BEGIN
SELECT
u.user_id user_id,
u.user_first_name as names,
u.user_last_name_01 as lastname1,
u.user_last_name_02 as lastname2,
MONTH(a.FECHA_ASISTENCIA) month,
COUNT(*) as absent_days,
p.PHONE as phone,
p.CITY as city,
#EDUCATION_LEVEL_ID
FROM
users u
inner join asistencia a ON u.user_id = a.USER_ID
inner join profile p ON u.rut_SF = p.RUT_SF
WHERE
a.ASISTENCIA = 0 -- NOT PRESENT
AND a.EDUCATION_LEVEL_ID = #EDUCATION_LEVEL_ID
AND YEAR(a.FECHA_ASISTENCIA) = #EDUCATION_LEVEL_YEAR
GROUP BY
u.user_id,
u.user_first_name,
u.user_last_name_01,
u.user_last_name_02,
MONTH(a.FECHA_ASISTENCIA),
p.TELEFONO,
p.CIUDAD_DOM
ORDER BY mes
END
ATTENDANCE
USER_ID
DATE
ATTENDANCE
EDUCATION_LEVEL_ID
123
2021-04-13
0
1
123
2021-04-14
1
1
DESIRED OUTPUT
names
lastname1
lastname2
month
absent_days
total_class_days
city
JOHN
SMITH
SMITH
3
10
24
CITY
JOHN
SMITH
SMITH
4
8
24
CITY
Without examples of what these tables look like, it is hard to give you a solid answer. However, it appears as though your biggest challenge is that ABSTENTIA does not exist.
This is a common problem for analysis - you need to create rows that do not exist (when the user was absent).
The general approach is to:
create a list of unique users
create a list of unique dates you care about
Cross Join (cartesian join) these to create every possible combination of user and date
Outer Join #3 to #4 so you can populate a PRESENT flag, and now you can see both who were PRESENT and which were not.
Filter out rows which don't apply (for instance if a user joined on 3/4/2021 then ignore the blank rows before this date)
You can accomplish this with some SQL that looks like this:
WITH GLOBAL_SPINE AS (
SELECT
ROW_NUMBER() OVER (ORDER BY NULL) as INTERVAL_ID,
DATEADD('DAY', (INTERVAL_ID - 1), '2021-01-01'::timestamp_ntz) as SPINE_START,
DATEADD('DAY', INTERVAL_ID, '2022-01-01'::timestamp_ntz) as SPINE_END
FROM TABLE (GENERATOR(ROWCOUNT => 365))
),
GROUPS AS (
SELECT
USERID,
MIN(DESIRED_INTERVAL) AS LOCAL_START,
MAX(DESIRED_INTERVAL) AS LOCAL_END
FROM RASGO.PUBLIC.RASGO_SDK__OP4__AGGREGATE_TRANSFORM__8AB1FEDF90
GROUP BY
USERID
),
GROUP_SPINE AS (
SELECT
USERID,
SPINE_START AS GROUP_START,
SPINE_END AS GROUP_END
FROM GROUPS G
CROSS JOIN LATERAL (
SELECT
SPINE_START, SPINE_END
FROM GLOBAL_SPINE S
WHERE S.SPINE_START BETWEEN G.LOCAL_START AND G.LOCAL_END
)
)
SELECT
G.USERID AS GROUP_BY_USERID,
GROUP_START,
GROUP_END,
T.*
FROM GROUP_SPINE G
LEFT JOIN {{ your_table }} T
ON DESIRED_INTERVAL >= G.GROUP_START
AND DESIRED_INTERVAL < G.GROUP_END
AND G.USERID = T.USERID;
The above script works on Snowflake, but the syntax might be slightly different depending on your RDBMS. There are also some other tweaks you can make regarding when you insert the blank rows, I chose 'local' which means that we begin inserting rows for each user on their very first day. You could change this to global if you wanted to populate data from every single day between 1/1/2021 and 1/1/2022.
I used Rasgo to generate this SQL
I'm having an issue when trying to join two tables though. It is Google Analytics data. In my first table I have google ads data, split by the dimensions campaign_id and date, then I have some metrics (impressions, clicks, and cost).
Something like:
Date
Campaign_ID
Clicks
Impressions
Cost
2019-08-01
13345
345
10,045
296
2019-08-02
12343
452
23,033
359
2019-08-03
132456
587
25,056
562
So far so good for my knowledge. I then have a 2nd table which has transactions in it, the transactions are individual transactions with the transaction ID so needs to be in a separate table. I have again the dimensions date and campaign_ID, plus transaction id. And metric of revenue. I'm not actually bothered about revenue, its just in my table but can be ingnored.
So 2nd table is:
Date
Campaign_ID
Transaction_ID
Revenue
2019-08-01
12343
A1100
5000
2019-08-01
12343
A1101
5000
What I'm trying to do with the data is count the number of transactions by date and campaign_ID and then join this to table 1 by date and campaign_ID.
My query to count the transactions is very straightforward:
SELECT
date,
campaign_ID
count(Transaction_ID) as transactions
From bqproject.tables.ga_ecom_data
GROUP BY Date, Campaign_ID
This gives exactly the data I need, and I can use a join with a seperate table to join the 1st table and the query above.
What I'm trying to achieve though is to put this in a single query so that I can pull the impressions, clicks and cost data, then count the transactions, and join them together by date and campaign_ID.
Hopefully that makes sense in terms of my query.
I was trying to use select (select but the error I've getting back states that nesting queries using select can only return a single column where as I'm trying to return 3. I've tried using select struct but I can't figure out the correct format, or if it is right.
So I've gone with another route (based on some youtube videos I've been following), the query here doesn't break, but I don't get my column "count_transaction_ID".
Here is the query I've used:
SELECT newdate,
CID,
AD_I,
Ad_Click,
AD_COST ,
FROM (SELECT Date as newdate, Campaign_ID as CID, SUM(Ad_Impressions) as AD_I, SUM(Ad_Clicks) as AD_Click, SUM(Ad_Cost) as AD_COST
from `bqproject.tables.ga_ads_data`
GROUP BY Date, Campaign_ID) A
JOIN
(
SELECT Date, Campaign_ID, COUNT(Transaction_ID)
FROM `bqproject.tables.ga_ecom_data`
group by Date, Campaign_ID
) B
ON A.newdate = B.Date
AND A.CID = B.Campaign_ID
LIMIT 1000
What I was trying to get back is a table such as:
Date
Campaign_ID
Clicks
Impressions
Cost
Count_Of_Transactions
2019-08-01
13345
345
10,045
296
5
2019-08-02
12343
452
23,033
359
16
2019-08-03
132456
587
25,056
562
10
But the table data which is returned doesn't show the count(transactions).
I don't know if I'm using the wrong structure here and should be using different subqueries, or if this isn't actually possibly to do. It feels like it should be, but it's just past my understanding at the moment.
You can group the columns required for display in the first table then join second table using count to roll up the transactions, something like:
SELECT
first.Campaign_ID,
first.Date,
first.Impressions,
first.Clicks,
first.Cost,
count(second.Transaction_ID) transactions
from `bqproject.tables.ga_ads_data` first
left join `bqproject.tables.ga_ecom_data` second
on first.Campaign_ID = second.Campaign_ID and first.Date = second.Date
group by
first.Campaign_ID,
first.Date,
first.Ad_Impressions,
first.Ad_clicks,
first.Ad_cost
order by first.Campaign_ID, first.Date
Looks like you just need to name the count column and then add it to the above call. See below:
SELECT newdate,
CID,
AD_I,
Ad_Click,
AD_COST , b.counttransactions
FROM (SELECT Date as newdate, Campaign_ID as CID, SUM(Ad_Impressions) as AD_I, SUM(Ad_Clicks) as AD_Click, SUM(Ad_Cost) as AD_COST
from `bqproject.tables.ga_ads_data`
GROUP BY Date, Campaign_ID) A
JOIN
(
SELECT Date, Campaign_ID, COUNT(Transaction_ID) as countTransactions
FROM `bqproject.tables.ga_ecom_data`
group by Date, Campaign_ID
) B
ON A.newdate = B.Date
AND A.CID = B.Campaign_ID
LIMIT 1000
you are pretty close!
SELECT A.newdate,
A.CID,
A.AD_I,
A.Ad_Click,
A.AD_COST,
B.transactions
FROM (SELECT Date as newdate,
Campaign_ID as CID,
SUM(Ad_Clicks) as AD_Click,
SUM(Ad_Cost) as AD_COST,
SUM(Ad_Impressions) as AD_I,
from `bqproject.tables.ga_ads_data`
GROUP BY Date, Campaign_ID
) A
left JOIN
(
SELECT Date, Campaign_ID, COUNT(distinct Transaction_ID) as transactions
FROM `bqproject.tables.ga_ecom_data`
group by Date, Campaign_ID
) B
ON A.newdate = B.Date
AND A.CID = B.Campaign_ID
Let me know if this helps! Naming helps a lot when using subqueries, you just needed to add B.transactions to the primary select statement.
PD1: Just a tip going forward, try to keep column names as consistent as possible and also try to avoid capitalization! It will help your development timeline.
PD2: Watch out using simple join, that kind of join will not select campaigns without transactionIds.
I want to return a table that consists of one column that contains only distinct projectid, a second column that displays the max(date) from within the given date-range and a third column that shows additional information. I'm still really new to sql.
Query:
select distinct (a.projectid), versiondate, newvalue
from a
inner join b on a.projectid = b.projectid
where b.contractor = 'SQA Contractor Company-1'
and a.attributename = 'Status'
and versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59'
group by a.projectid, versiondate, newvalue
order by versiondate
What it's returning:
projectid | versiondate | newvalue
-----------+------------------------+--------------------
p27641 | 2014 10 01 12:23:18 | In work
p27641 | 2014 10 01 12:23:21 | In billing
p27641 | 2014 10 01 12:23:45 | completed
p19397 | 2014 10 01 12:25:03 | pending review
p19397 | 2014 10 01 12:25:42 | pending assignment
p10397 | 2014-10-01 12:26:18 | pending-acceptance
What I want it to return:
only the distinct projectid's that represent the most recent versiondate. I need to see what the newvalue was on the most recent date for each distinct projectid.
Trying to put that into words was kind of tough so hopefully I explained my question well. Any help/criticism is accepted.
This sort of question needs to be approached in multiple steps.
First, find the most reason version date for each project, then find the corresponding new value.
select a.projectid, a.max_versiondate, b.newvalue
from
(select a.projectid, max(b.versiondate) max_versiondate
from a
inner join b
on a.projectid = b.projectid
where b.contractor = 'SQA Contractor Company-1'
and a.attributename = 'Status'
and b.versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59'
group by
a.project id) a
inner join b
on b.projectid = a.projectid
and b.versiondate = a.max_versiondate
Another option is to use window aggregate methods to find the max value inline, and filter based on that.
select *
from
(
select a.projectid, versiondate, newvalue, ROW_NUMBER() OVER(PARTITION BY projectid ORDER BY versiondate DESC) rn
from a
inner join b on a.projectid = b.projectid
where b.contractor = 'SQA Contractor Company-1'
and a.attributename = 'Status'
and versiondate between '2014-10-01 00:00:00' and '2014-10-01 23:59:59'
group by a.projectid, versiondate, newvalue
order by versiondate
)
where rn = 1
both should give you the same results, it's a matter of your indexing and table size to see which is most effective.
This can be simpler with the Postgres-specific DISTINCT ON.
SELECT DISTINCT ON (a.projectid)
a.projectid, b.versiondate, b.newvalue
FROM a
JOIN b USING (projectid)
WHERE a.attributename = 'Status'
AND b.contractor = 'SQA Contractor Company-1'
AND b.versiondate >= '2014-10-01 0:0'
AND b.versiondate < '2014-10-02 0:0'
ORDER BY a.projectid, b.versiondate DESC;
The SQL-standard DISTINCT folds duplicates on the whole row. As an extension to this Postgres implemented DISTINCT ON to fold duplicates on selected columns. For other columns in the SELECT list the value from the (consistent) first row is picked, defined by ORDER BY, or arbitrary if not well-defined.
You had an misleading halfbreed of both constructs. The parentheses in your query would make sense in combination with DISTINCT ON, but hardly die DISTINCT. Detailed explanation:
Select first row in each GROUP BY group?
Other points
You don't need GROUP BY in this case.
Ranges on timestamps are typically best expressed with including lower and excluding upper bound. BETWEEN .. AND includes both bounds and is not good for this:
Select a date range from a timestamp column
Since you picked meaningful column names, you join conveniently join with the USING construct.
I have two joined tables, parent one shows unit's name, child shows recording temperatures, that can be inserted either by automatic process (AUTO) or by user. So for given unit reading records from simple join would look like
UNIT TEMP TIMESTAMP DATA_SOURCE
ABC -20 10:26 AUTO
ABC -19 11:27 USER
ABC -19 11:27 AUTO
The goal is to select the latest temp reading. I can use subquery to do so:
SELECT A.UNIT, B.TEMP, B.TIMESTAMP,B.DATA_SOURCE
FROM units_table A left outer join readings_table B on A.Gkey=B.unit_gkey
WHERE B.TIMESTAMP=
(SELECT MAX(TIMESTAMP) FROM readings_table B1
WHERE A.Gkey=B1.unit_gkey)
It would be simple but in the example above there are two exact timestamps, so I will get TWO readings. In such case I'd like to ignore the AUTO source. Is there an elegant way to do it?
Edit: to be clear I want only ONE ROW result:
ABC -19 11:27 USER
You can do this with row_number() instead:
SELECT ut.UNIT, rt.TEMP, rt.TIMESTAMP, rt.DATA_SOURCE
FROM units_table ut left outer join
(SELECT rt.*,
row_number() over (partition by rt.unit_Gkey
order by timestamp desc,
(case when rt.data_source = 'AUTO' then 1 else 0 end)
) as seqnm
FROM readings_table rt
) rt
on rt.unit_Gkey = ut.gkey
WHERE rt.seqnum = 1;
Note: if you wanted the duplicates, you would use rank() or dense_rank() instead of row_number() (and remove the second clause in the order by).
http://www.w3schools.com/sql/sql_distinct.asp
just use the distinct key word look at the example! :)
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;