SQL order by 100% not ordering first - sql

I have a query that shows my counter's accuracy and I'm doing a simple order by accuracy. But, what is happening it is ordering correctly BUT 100% appears at the bottom and not in correct order. I have moved the order by, but I may be missing something?
QUERY:
select counted_by_user_id, total, defects, trunc((total-defects)/total*100,2)||'%' as accuracy from
(
select counted_by_user_id, sum(locations) as total, sum(numberOfDefectBins) as defects from
(
select counted_by_user_id, locations, numberOfDefectBins from
(
select trunc(ical.last_updated_date_utc) as CountDate,ip.process_name,ipl.icqa_process_id,ical.counted_by_user_id,count(*) as locations, (
SELECT COUNT(iid.icqa_ical_detail_id)
FROM icqa_process_locations ipl1, icqa_count_attempt_logs ical1, icqa_ical_details iid
WHERE ipl1.icqa_process_id = ipl.icqa_process_id
AND ical1.icqa_count_attempt_id = ipl1.icqa_count_attempt_id
AND ical1.counted_by_user_id = ical.counted_by_user_id
AND iid.icqa_count_attempt_log_id = ical1.icqa_count_attempt_log_id
AND iid.is_defective = 'Y' and trunc(ipl1.last_updated_date_utc) = trunc(sysdate)) as numberOfDefectBins
from icqa_count_attempt_logs ical left join icqa_process_locations ipl
on ical.icqa_count_attempt_id = ipl.icqa_count_attempt_id
left join ICQA_PROCESSES ip on ipl.icqa_process_id= ip.icqa_process_id
where trunc(ical.last_updated_date_utc) = trunc(sysdate)
AND ical.counted_by_user_id IS NOT NULL
group by trunc(ical.last_updated_date_utc), ip.process_name, ipl.icqa_process_id, ical.counted_by_user_id
order by ical.counted_by_user_id
))
group by counted_by_user_id
)
order by accuracy desc;
RESULT:
counted_by_user_id total defects accuracy
dggonza 346 1 99.71%
giermanc 225 1 99.55%
kylecoll 659 4 99.39%
manansal 71 1 98.59%
jssuarez 271 5 98.15%
jhheredi 464 10 97.84%
tabilinl 185 4 97.83%
darinc 102 3 97.05%
tostab 484 18 96.28%
alicmena 25 1 96%
reyesk 733 31 95.77%
genej 478 22 95.39%
yadirac 73 4 94.52%
lhherold 505 28 94.45%
anamarih 465 30 93.54%
pineiror 380 25 93.42%
nallelys 349 31 91.11%
almquij 112 12 89.28%
kustance 357 50 85.99%
arteagaa 54 12 77.77%
gardne 848 0 100%
willij 5 0 100%
castnera 21 0 100%
pbarbara 43 0 100%
caudilr 493 0 100%
jennifei 27 0 100%

Of course. Because you are sorting a string not a number.
There are multiple solutions:
order by length(accuracy) desc, accuracy;
is probably the easiest.
Some others:
order by cast(replace(accuracy, '%', '') as float);
order by (total-defects)/total;
order by (case when accuracy = '100%' then 1
when accuracy >= '10%' then 2
else 3
end), accuracy desc

Related

How to find a specific value in consecutive date

I need your help for a little issue.
I use MS ACCESS to work with a database and I need to resolve a query. My query asks:
Find the CUSTOMER_ID and TRANSC_ID where 2 consecutive value between 200 and 500 WITHIN the same transc_id.
I explain.
I have this table in this format:
CUSTOMER_ID TRANSC_ID VALUE VALUE_DATE
51 10 15 29-12-1999
51 10 20 15-07-2000
51 10 35 18-08-2000
51 10 250 30-08-2000
51 10 13 10-09-2000
51 10 450 15-09-2000
51 11 5 15-09-2000
51 11 23 30-09-2000
51 11 490 10-10-2000
51 11 300 12-10-2000
51 11 85 30-10-2000
51 11 98 01-01-2000
53 10 65 15-10-2000
53 10 14 29-12-2000
And I need just
51 11 490 10-10-2000
51 11 300 12-10-2000
because the two values is consecutive (and both of them is >250 and <500).
How can I make a query in MS ACCESS to obtain this result?
Thank you.
You can get the "next" and "previous" values using correlated subqueries, and then do the comparison:
select t.*
from t
where t.value between 200 and 500 and
( (select top 1 t2.value
from t as t2
where t2.CUSTOMER_ID = t.CUSTOMER_ID and t2.TRANSC_ID = t.TRANSC_ID and
t2.value_date > t.value_date
order by t2.value_date
) between 200 and 500 or
(select top 1 t2.value
from t as t2
where t2.CUSTOMER_ID = t.CUSTOMER_ID and t2.TRANSC_ID = t.TRANSC_ID and
t2.value_date < t.value_date
order by t2.value_date desc
) between 200 and 500
);

SQL Multiple WHERE Clauses against one table, with CASE statements

I wrote this query and it seems to be working to gather correct results, however, it also takes a VERY long time. I'm just wondering if there is a way to make it more efficient?
(I understand that it's inefficient because it is creating data tables and joining them back together - I just don't know how to get around it, specifically with the CASE issue included).
I'm working in Excel with an ODBC connection to AS400. The question marks allow user-entered parameters within Excel cells.
with W as
(
select yr as YEAR, pd as PERIOD, sum(amt1 + amt2 + amt3 + amt4) as SALES
from TABLE
group by yr, pd
order by yr desc, pd desc
), X as
(
select yr as YEAR, pd as PERIOD, sum(amt1 + amt2 + amt3 + amt4) as BSALES
from TABLE
where type = 'B'
group by yr, pd
order by yr desc, pd desc
), Y as
(
select
CASE WHEN pd = 1 THEN yr - 1 ELSE yr END as YEAR,
CASE WHEN pd = 1 THEN 12 ELSE pd - 1 END as PERIOD,
SUM(OM) as MODOM
from TABLE
group by yr, pd
order by yr desc, pd desc
), Z as
(
select
CASE WHEN pd = 1 THEN yr - 1 ELSE yr END as YEAR,
CASE WHEN pd = 1 THEN 12 ELSE pd - 1 END as PERIOD,
SUM(BOM) as BMODOM
from TABLE
where type = 'B'
group by yr, pd
order by yr desc, pd desc
)
select w.YEAR, w.PERIOD, w.SALES, x.BSales, y.MODOM, z.BMODOM
from w inner join x
on w.YEAR = x.YEAR and w.PERIOD = x.PERIOD
inner join y
on w.YEAR = y.YEAR and w.PERIOD = y.PERIOD
inner join z
on w.YEAR = z.YEAR and w.PERIOD = z.PERIOD
where w.YEAR between ? and ? and w.PERIOD between ? and ?
order by YEAR desc, PERIOD desc
I had to change the code slightly for privacy purposes, but I believe this all relays correctly.
Example Data:
Yr Pd Type Amt OM
18 2 A 45 181
18 2 B 33 163
18 2 A 40 153
18 1 B 39 136
18 1 B 24 142
18 1 B 53 143
18 1 A 41 186
18 1 A 78 197
17 12 A 98 139
17 12 A 54 159
17 12 B 78 181
17 12 B 45 101
17 11 A 28 134
17 11 A 77 192
17 11 A 75 110
17 11 B 60 135
17 11 B 83 170
17 10 B 72 114
17 10 A 26 118
17 10 A 95 111
17 9 A 12 112
17 9 B 14 171
Example Results
Yr Pd Sales Bsales MODOM BMODOM
18 2 118 33 804 421
18 1 235 116 580 282
17 12 275 123 741 305
17 11 323 143 343 114
17 10 193 72 283 171
Note that I need SALES at a TOTAL Level, and then at a TYPE B level. I also need OM at a TOTAL Level, and then also a Type B level - HOWEVER - I need to offset by one period. So the MODOM is for 17-10 is reflection of the OM total for period 17-9 in the table. (I hope that make sense).
EDIT I have this backward. The MODOM for 17-10 would actually reflect the OM value for 17-11, not the other way. Corrected EXPECTED RESULTS.
Yr Pd Sales Bsales MODOM BMODOM
18 2 118 33 0 0
18 1 235 116 497 163
17 12 275 123 804 421
17 11 323 143 580 282
17 10 193 72 741 305
So using Conditional aggregation you can at least get rid of 2 of your common table expressions which will help. Not ordering until your final presentation query instead of in each common table expression will help too. Using an actual date e.g. First of First Month of a Period could help eliminate what the potentially costly case expressions when defining previous period.
There are a few ways of writing this but this will give you an example of conditional aggregation.
And note the LEFT JOIN rather than INNER because your 1st period will always drop off your query if you use INNER
WITH PeriodSales AS(
SELECT
yr as YEAR
,pd AS PERIOD
,SUM(amt) as SALES
,SUM(CASE WHEN type = 'B' THEN amt END) as BSALES
FROM
Table
GROUP BY
yr
,pd
)
, PreviousPeriod AS
(
SELECT
CASE WHEN pd = 12 THEN yr + 1 ELSE yr END as YEAR
,CASE WHEN pd = 12 THEN 1 ELSE pd + 1 END as PERIOD
,SUM(OM) as MODOM
,SUM(CASE WHEN type = 'B' THEN OM END) as BMODOM
FROM
Table
GROUP BY
CASE WHEN pd = 12 THEN yr + 1 ELSE yr END
,CASE WHEN pd = 12 THEN 1 ELSE pd + 1 END
)
SELECT
ps.YEAR
,ps.PERIOD
,ps.SALES
,ps.BSALES
,pp.MODOM
,pp.BMODOM
FROM
PeriodSales ps
LEFT JOIN PreviousPeriod pp
ON ps.YEAR = pp.YEAR
AND ps.PERIOD = pp.PERIOD
ORDER BY
ps.YEAR DESC
,ps.PERIOD DESC
Per your edits, to align to the "Previous Period" to get to the OM amounts you want you will actually want to ADD a period not subtract one in the example I used. I have tested this and it does work. There can be many other factors for performance that we cannot discover without knowing more about the tables and execution plans etc.

Calculate Sub Query Column Based On Calculated Column

I have a table ScheduleRotationDetail that contains these as columns:
ScheduleRotationID ScheduleID Ordinal Duration
379 61 1 1
379 379 2 20
379 512 3 1
379 89 4 20
I have a query that goes like this in order to get the day of the year each schedule is supposed to start on:
SELECT ScheduleID, Ordinal, Duration,
,Duration * 7 AS DurationDays
,( SELECT ( ISNULL( SUM(ISNULL( Duration, 0 )), 0 ) - 1 ) * 7
FROM ScheduleRotationDetail WHERE ScheduleRotationID = srd.ScheduleRotationID
AND Ordinal <= srd.Ordinal ) AS StartDay
FROM ScheduleRotationDetail srd
WHERE srd.ScheduleRotationID = 379
That outputs this as the result set:
ScheduleID Ordinal Duration DurationDays StartDay
61 1 1 7 0
379 2 20 140 140
512 3 1 7 147
89 4 20 140 287
Yet what I need the start day column values to be are:
0
7
147
154
I have tried CTEs but can't get it to work so I've come to here for advice.
It looks like you want a cumulative sum. In SQL Server 2012+, you can do:
SELECT ScheduleID, Ordinal, Duration,
SUM(Duration*7) OVER (ORDER BY Ordinal) - Duration*7 as StartDate
FROM ScheduleRotationDetail srd ;
In earlier versions, you can use APPLY for this purpose (or a correlated subquery).

T-SQL Group by day date but i want show query full date

I want to show the date field can not group.
My Query:
SELECT DAY(T1.UI_CreateDate) AS DATEDAY, SUM(1) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1 WHERE T1.UI_BR_BO_ID = 45
GROUP BY DAY(T1.UI_CreateDate)
Result:
DATEDAY TOTALCOUNT
----------- -----------
15 186
9 1
3 2
26 481
21 297
27 342
18 18
30 14
4 183
25 553
13 8
22 469
16 1
17 28
20 331
28 90
14 33
8 1
But i want to show the full date...
Example result:
DATEDAY TOTALCOUNT
----------- -----------
15/06/2015 186
9/06/2015 1
3/06/2015 2
26/06/2015 481
21/06/2015 297
27/06/2015 342
18/06/2015 18
30/06/2015 14
4/06/2015 183
25/06/2015 553
13/06/2015 8
22/06/2015 469
16/06/2015 1
17/06/2015 28
20/06/2015 331
28/06/2015 90
14/06/2015 33
8/06/2015 1
I want to see the results...
I could not get a kind of results...
How can I do?
Thanx!
How about just casting to date to remove any time component:
SELECT CAST(T1.UI_CreateDate as DATE) AS DATEDAY, COUNT(*) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1
WHERE T1.UI_BR_BO_ID = 45
GROUP BY CAST(T1.UI_CreateDate as DATE)
ORDER BY DATEDAY;
SUM(1) for calculating the count does work. However, because SQL has the COUNT(*) function, it seems a bit awkward.
So you can group by DAY(T1.UI_CreateDate) or use full date for grouping. But these are different . As both these dates '2015-04-15' and '2015-12-15' result in same DAY value of 15.
Assuming you want to group on DAY rather than date please try the below version of query:
SELECT DISTINCT
T1.UI_CreateDate as DATEDAY,
count(1) over (PARTITION BY DAY(T1.UI_CreateDate) ) AS TOTALCOUNT
FROM mydb.dbo.LP_UseImpression T1 WHERE T1.UI_BR_BO_ID = 45
sql fiddle for demo: http://sqlfiddle.com/#!6/c3337/1

Microsoft access Query rolling total every 5 lines not using dates

I am new to Microsoft access.
I need a query that will allow me to sum a rolling total for every 5 lines of data. So on the sixth day I need a line to drop off the total and the new line to be added.
Fields:
ID, Daily_SUM
The results should be
ID Daily sum Weekly Sum
1 12
2 41
3 46
4 125
5 120 344
6 42 374
7 41 374
8 57 385
9 207 467
10 215 562
11 187 707
12 -43 623
13 45 611
14 56 460
15 40 285
16 8 106
17 95 244
18 580 779
19 360 1083
20 337 1380
You can do this with a correlated subquery. The challenge is actually getting NULL values on the first few rows:
select t.id, t.daily,
(select iif(count(*) = 7, sum(t3.daily), NULL)
from (select top 7 t2.daily
from table t2
where t2.id <= t.id
order by t2.id desc
) t3
) as weekly
from table t;
EDIT:
If we assume that the ids are assigned sequentially with no gaps, then you can use an explicit join:
select t.id, t.daily,
iif(count(*) = 7, sum(t2.daily), NULL) as weekly
from table t inner join
table t2
on t2.id between t.id - 6 and t.id
group by t.id, t.daily;