SQL - Group and count duplicates row - mysql

I have no idea how to group and count duplicates row on mysql
below is the result that I got from my query
ssn + checktime + nama
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'196702031989031001' + '2018-08-03 07:33:02' + 'FAJAR PERMADI'
'196810021993031001' + '2018-08-01 07:33:25' + 'ANDRI ANGGORO, SH'
'196911052000031001' + '2018-08-03 07:47:22' + 'SEMI TEDDY RORY, SS'
'196912221994032001' + '2018-08-01 08:03:59' + 'AI SALATUN'
'196912221994032001' + '2018-08-02 09:34:11' + 'AI SALATUN'
'196912221994032001' + '2018-08-03 07:33:18' + 'AI SALATUN'
'197012051993031001' + '2018-08-01 07:58:47' + 'AHMAD SODIKIN, SH'
'197012192001121001' + '2018-08-01 09:54:21' + 'JUARA PAHALA MARBUN, ST'
'197012192001121001' + '2018-08-02 09:39:41' + 'JUARA PAHALA MARBUN, ST'
and below is my query
SELECT a.ssn, a.checktime, b.nama
FROM hki_kepegawaian.fo_absensi a
left join hki_kepegawaian.fo_pegawai b on a.ssn = b.nip
where (substring(cast(checktime as DATE), 6, 2) = '08')
and (cast(a.checktime as TIME)) >= '07:30:00' and (cast(a.checktime as
TIME)) <= '10:00:00'
and (substring(golongan, 1, 2)) NOT IN ('IV')
group by ssn, cast(a.checktime as date)
and below is result that I expected
ssn + checktime + nama + total
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'196702031989031001' + '2018-08-03 07:33:02' + 'FAJAR PERMADI' + 1
'196810021993031001' + '2018-08-01 07:33:25' + 'ANDRI ANGGORO, SH' + 1
'196911052000031001' + '2018-08-03 07:47:22' + 'SEMI TEDDY RORY, SS' + 1
'196912221994032001' + '2018-08-01 08:03:59' + 'AI SALATUN' + 3
'197012051993031001' + '2018-08-01 07:58:47' + 'AHMAD SODIKIN, SH' + 1
'197012192001121001' + '2018-08-01 09:54:21' + 'JUARA PAHALA MARBUN, ST' + 2

Your expected output implies that you want to report the record having the earliest check time for each ssn/nama group of records. For the count, it just looks like the total number of records in each group.
SELECT
a.ssn,
MIN(CAST(a.checktime AS date)) AS checktime,
b.nama,
COUNT(*) AS total
FROM hki_kepegawaian.fo_absensi a
LEFT JOIN hki_kepegawaian.fo_pegawai b
ON a.ssn = b.nip
WHERE
MONTH(checktime) = 8 AND
CAST(a.checktime AS TIME) BETWEEN '07:30:00' AND '10:00:00' AND
SUBSTRING(golongan, 1, 2)) <> 'IV'
GROUP BY
a.ssn, CAST(a.checktime AS date);

I agree with Tim that you seem to want to take the earliest time. This is accomplished with a group by in this case.
However, there are some other fixes to the query that I would suggest:
Do not use string operations on date/times.
Use meaningful table aliases that are abbreviations for the table.
Include all unaggregated columns in the GROUP BY.
Use LIKE where appropriate.
So, I would suggest:
SELECT a.ssn, a.checktime, p.nama
FROM hki_kepegawaian.fo_absensi a LEFT JOIN
hki_kepegawaian.fo_pegawai b
ON a.ssn = p.nip
WHERE MONTH(checktime) = 8 AND
CAST(a.checktime as TIME) >= '07:30:00' AND
CAST(a.checktime as TIME)) <= '10:00:00' AND
golongan NOT LIKE 'IV%'
GROUP BY a.ssn, p.nama;

Look into count() function.
I can't check whether it works, but try the following query:
SELECT a.ssn, a.checktime, b.nama, count(*) as total
FROM hki_kepegawaian.fo_absensi a
left join hki_kepegawaian.fo_pegawai b on a.ssn = b.nip
where (substring(cast(checktime as DATE), 6, 2) = '08')
and (cast(a.checktime as TIME)) >= '07:30:00' and (cast(a.checktime as
TIME)) <= '10:00:00'
and (substring(golongan, 1, 2)) NOT IN ('IV')
group by ssn, nama
Having total>=1

Related

Get rank in a score table

how to rank in myqsl?
sample code:
SELECT
contestant_tbl.contestant_num,
contestant_tbl.fn,
contestant_tbl.ln,
tally_j1_tbl.c1_score + tally_j1_tbl.c2_score AS j1_total,
tally_j2_tbl.c1_score + tally_j2_tbl.c2_score AS j2_total
FROM
contestant_tbl
LEFT JOIN tally_j1_tbl ON contestant_tbl.contestant_num = tally_j1_tbl.contestant_num
LEFT JOIN tally_j2_tbl ON contestant_tbl.contestant_num = tally_j2_tbl.contestant_num
GROUP BY
contestant_tbl.contestant_num
i wanted to have an additional column total and rank.
Hope this is what you are looking for.
SELECT
contestant_tbl.contestant_num,
contestant_tbl.fn,
contestant_tbl.ln,
tally_j1_tbl.c1_score + tally_j1_tbl.c2_score AS j1_total,
tally_j2_tbl.c1_score + tally_j2_tbl.c2_score AS j2_total
j1_total + j2_total AS total,
RANK () OVER (
ORDER BY total DESC
) rank
FROM
contestant_tbl
LEFT JOIN tally_j1_tbl ON contestant_tbl.contestant_num = tally_j1_tbl.contestant_num
LEFT JOIN tally_j2_tbl ON contestant_tbl.contestant_num = tally_j2_tbl.contestant_num
GROUP BY
contestant_tbl.contestant_num
We cannot guess your database structure according to your question. However, there are couple of noticeable issues.
Please take a look at the corrected query (rankings included):
set #num = 0;
SELECT
contestant_tbl.contestant_num,
contestant_tbl.fn,
contestant_tbl.ln,
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) AS j1_total,
sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0)) AS j2_total,
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) + sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0)) AS total,
#num := #num + 1 as pos
FROM
contestant_tbl
LEFT JOIN tally_j1_tbl ON contestant_tbl.contestant_num = tally_j1_tbl.contestant_num
LEFT JOIN tally_j2_tbl ON contestant_tbl.contestant_num = tally_j2_tbl.contestant_num
GROUP BY
contestant_tbl.contestant_num
ORDER BY
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) + sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0))
Numerical values that can be NULL should be coalesced prior sum opperation. (e.g. coalesce(tally_j2_tbl.c2_score, 0)).
Your query contains group by, but doesn't contain any aggregate function. I assume that sum should be used.
Ranking is achieved by utilizing MySQL variables. It is for older MySQL versions. MySQL 8 introduced RANK function so it is easier and cleaner:
SELECT
contestant_tbl.contestant_num,
contestant_tbl.fn,
contestant_tbl.ln,
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) AS j1_total,
sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0)) AS j2_total,
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) + sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0)) AS total,
RANK() OVER (
ORDER BY sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) + sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0))
) as pos
FROM
contestant_tbl
LEFT JOIN tally_j1_tbl ON contestant_tbl.contestant_num = tally_j1_tbl.contestant_num
LEFT JOIN tally_j2_tbl ON contestant_tbl.contestant_num = tally_j2_tbl.contestant_num
GROUP BY
contestant_tbl.contestant_num
ORDER BY
sum(coalesce(tally_j1_tbl.c1_score, 0)) + sum(coalesce(tally_j1_tbl.c2_score, 0)) + sum(coalesce(tally_j2_tbl.c1_score, 0)) + sum(coalesce(tally_j2_tbl.c2_score, 0))

mysql average of best three

I have pieced this together from sites online and it works but not completely, what i need it to do is take the top 3 results and average them but it takes ALL results, can anyone point me in the right direction?
SELECT i.NAME,
e.comp,
Round(Avg(c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6), 2) AS "Average Score",
( CASE
WHEN compID = '7' THEN Concat(Round(Avg(
( (
c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6 ) / 400 ) * 100), 2), ' %')
WHEN compID = '5' THEN Concat(Round(Avg(
( (
c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6 ) / 600 ) * 100), 2), ' %')
WHEN compID = '3' THEN
Concat(Round(Avg(( ( c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6 ) / 600 ) * 100), 2), ' %')
ELSE 'Unspecified'
END ) AS "Average as Percent"
FROM jos_practicedetail c,
jos_comps e,
jos_practice g,
jos_members i
WHERE e.compsid = g.competition
AND g.practiceid = c.practicepid
AND i.memberid = c.competitorid
AND g.typeID = '2'
AND Year(g.pdate) = '2017'
AND (SELECT Count(*)
FROM jos_practicedetail b
WHERE b.competitorid = c.competitorid
AND b.practicepid = c.practicepid
AND ( b.phase1 + b.phase2 + b.phase3 + b.phase4 + b.phase5
+ b.phase6 ) >= (
c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6 )) <= 3
GROUP BY competitorid
HAVING Count(*) > 2
ORDER BY competitorid,
( Avg(c.phase1 + c.phase2 + c.phase3 + c.phase4 + c.phase5
+ c.phase6) ) DESC

SUM selected columns using alias and group by

I'm trying to perform calculations on select columns using aliases and a grouping by. Query is below(problem on line before the from):
select r.res_id,
r.arrive_date,
r.depart_date,
r.res_type,
if(DATEDIFF(r.depart_date, r.arrive_date) >29, 'LT', 'ST') as 'StayType',
SUM(r.rent + r.fee_arr_early + r.fee_dep_late + r.fee_peace_waiver + r.fee_pool + r.city_tax + r.fee_cleaning + r.fee_pet + r.fee_tshirt + r.fee_misc + r.fee_non_tax + r.fee_processing + r.fee_travel_ins + r.fee_event + r.fee_cancel) as 'folioTotal',
coalesce((select SUM(g.amount) from guest_payments as g where g.resId = r.res_id and charge_type = 'charge' and approved = 'Y'),0) as 'payments',
coalesce((select SUM(g.amount) from guest_payments as g where g.resId = r.res_id and charge_type = 'credit' and approved = 'Y'),0) as 'credits',
(SUM('folioTotal') - SUM('payments') + SUM('credits')) as 'folioBalance'
from reservations as r
join guest_payments as g
on r.res_id = g.resId
group by r.res_id
I've tried putting this inside another sum with the same outcome.
I was being stupid, I was referencing the aliases inside single ticks which is why it wasn't calculating. Solution:
select r.res_id,
r.arrive_date,
r.depart_date,
r.res_type,
g.entry_date,
if(DATEDIFF(r.depart_date, r.arrive_date) >29, 'LT', 'ST') as 'StayType',
(select SUM(r.rent + r.fee_arr_early + r.fee_dep_late + r.fee_peace_waiver + r.fee_pool + r.city_tax + r.fee_cleaning + r.fee_pet + r.fee_tshirt + r.fee_misc + r.fee_non_tax + r.fee_processing + r.fee_travel_ins + r.fee_event + r.fee_cancel) from reservations as r where r.res_id = g.resId) as 'folioTotal',
coalesce((select SUM(g.amount) from guest_payments as g where g.resId = r.res_id and charge_type = 'charge' ),0) as 'payments',
coalesce((select SUM(g.amount)* -1 from guest_payments as g where g.resId = r.res_id and charge_type = 'credit' and approved = 'Y'),0) as 'credits',
(select folioTotal - payments + credits)
from reservations as r
join guest_payments as g
on r.res_id = g.resId
group by r.res_id

altering a table using sql

I have this table
**Original Table**
year month duration amount per month
2012 5 3 2000
and I want to get this
**Result table**
year month duration amount per month
2012 5 1 2000
2012 6 1 2000
2012 7 1 2000
Note how the duration of a project (this is a project) is 3 and the "amount per month" is 2000, so I added two more rows to show that the next months (6 and 7) will have an "amount per month" as well. How do I do that with sql/tsql?
try this for SQL SERVER, i included my test temp table:
declare #temp as table
(
[year] int
, [month] int
, [duration] int
, [amount] int
)
insert into #temp
(
[year]
, [month]
, [duration]
, [amount]
)
VALUES(
2012
,5
,3
,2000
)
SELECT
[year]
,[month] + n.number
,1
,[amount]
, '1' + SUBSTRING(CAST([duration] AS varchar(10)), 2, 1000) AS Items
FROM #temp
JOIN master..spt_values n
ON n.type = 'P'
AND n.number < CONVERT(int, [duration])
Please see the script below that may work for your requirement. I have also compensated for calender year and month increment. Please test and let me know.
DECLARE #temp AS TABLE([Year] INT,[Month] INT,Duration INT,Amount INT)
INSERT INTO #temp([year], [month], Duration, Amount)
VALUES (2011, 5, 3, 2000),(2012, 11, 3, 3000),(2013, 9, 12, 1000);
;WITH cte_datefix
AS (
SELECT [Year],
[Month],
Duration,
Amount,
CAST(CAST([Year] AS VARCHAR(4)) + RIGHT('00' + CAST([Month] AS VARCHAR(2)), 2) + '01' AS DATE) AS [Date]
FROM #temp
),
cte_Reslut
AS (SELECT [Year],
[Month],
Duration,
Amount,
[Date],
1 AS Months
FROM cte_datefix
UNION ALL
SELECT t.[Year],
t.[Month],
t.Duration,
t.Amount,
DATEADD(M, Months, t.[Date]) AS [Date],
cr.Months + 1 AS Months
FROM cte_Reslut AS cr
INNER JOIN cte_datefix AS t
ON t.[Year] = cr.[Year]
WHERE cr.Months < cr.Duration
)
SELECT YEAR([Date]) AS [Year],
MONTH([Date]) AS [Month],
1 AS Duration,
Amount
FROM cte_Reslut
ORDER BY [Date]
For those that are wondering how to increment the year if needed, here is an example building on Suing response (really easy, just include two case statements):
select
2012 as [year]
,11 as [month]
,5 as [duration]
,2000 as [amount]
into #temp
select * from #temp
SELECT
case
when [month] + n.number > 12
then [year] + 1
else [year]
end as [year]
,case
when [month] + n.number > 12
then [month] + n.number - 12
else [month] + n.number
end as newYear
,1 as newDuration
,[amount]
, '1' + SUBSTRING(CAST([duration] AS varchar(10)), 2, 1000) AS Items
FROM #temp
JOIN master..spt_values n
ON n.type = 'P'
AND n.number < CONVERT(int, [duration])
drop table #temp

How to sum all titles even others are empty

my query objective is to sum all the fields from (3) tables but i have some problem in generating the final_total_sum output if some of the other titles empty the final_total_sum is empty....but if all titles are not empty my query generate final_total_sum(output).
I wan to do is even other titles are empty my query can still generate a final_total_sum(output).
http://s38.photobucket.com/user/eloginko/media/output_zpsfcab9d54.png.html
current query:
SELECT *,
ROUND(interview_sum +
other_sum +
edu_attain2_sum +
experience2_sum +
trainings2_sum +
eligibility2_sum) AS final_total_sum
FROM (
SELECT
ROUND((SELECT SUM(t2.inttotal)
FROM app_interview2 AS t2
WHERE t2.atic = t.atic)/7,1)
AS interview_sum,
ROUND((SELECT SUM(o2.ototal)
FROM other_app2 AS o2
WHERE o2.oaic = t.atic)/7,1)
AS other_sum,
ROUND((SELECT SUM(s1.edu_attain2)
FROM qual_stan2 AS s1
WHERE s1.oaic2 = t.atic)/7,1)
AS edu_attain2_sum,
ROUND((SELECT SUM(s2.experience2)
FROM qual_stan2 AS s2
WHERE s2.oaic2 = t.atic)/7,1)
AS experience2_sum,
ROUND((SELECT SUM(s3.trainings2)
FROM qual_stan2 AS s3
WHERE s3.oaic2 = t.atic)/7,1)
AS trainings2_sum,
ROUND((SELECT SUM(s4.eligibility2)
FROM qual_stan2 AS s4
WHERE s4.oaic2 = t.atic)/7,1)
AS eligibility2_sum,
t.atid,
t.atic,
t.atname,
t.region,
t.town,
t.uniq_id,
t.position,
t.salary_grade,
t.salary
FROM app_interview2 AS t
WHERE uniq_id = '$q'
GROUP BY t.atname
HAVING COUNT(DISTINCT t.atic)) subq
Try:
ROUND( ifnull(interview_sum,0) +
ifnull(other_sum,0) +
ifnull(edu_attain2_sum,0) +
ifnull(experience2_sum,0) +
ifnull(trainings2_sum,0) +
ifnull(eligibility2_sum,0)) AS final_total_sum
In SQL x + NULL always gives NULL, ifnull function converts nulls to 0
use like SUM(ifnull(t2.inttotal,0))