I'm in the process of validating the following query where my expected result is a row with a revenue value of 0 for any week where there is no revenue to SUM. What I'm getting is only one 0 revenue record where I know there are many. Can someone take a look at my code and see if there is anything obvious I screwed up?
SELECT dbo.LMCustomer.Name,
SUM(dbo.LMDelivery.LdryCensChrg + dbo.LMDelivery.LdryWghtChrg + dbo.LMDelivery.LdryPiecChrg - dbo.LMDelivery.RetnWghtCred - dbo.LMDelivery.RetnPiecCred - dbo.LMDelivery.VrncChrg + dbo.LMDelivery.LdryDelvChrg +
dbo.LMDelivery.PrchChrg + dbo.LMDelivery.LdryPcntChrg + dbo.LMDelivery.AuxpChrg01 + dbo.LMDelivery.AuxpChrg02 + dbo.LMDelivery.AuxpChrg03 + dbo.LMDelivery.AuxpChrg04 + dbo.LMDelivery.AuxpChrg05 + dbo.LMDelivery.AuxpChrg06
+ dbo.LMDelivery.AuxpChrg07 + dbo.LMDelivery.AuxpChrg08 + dbo.LMDelivery.AuxpChrg09 + dbo.LMDelivery.AuxpChrg10 + dbo.LMDelivery.AuxpChrg11 + dbo.LMDelivery.AuxpChrg12 - dbo.LMDelivery.AuxpCred01 - dbo.LMDelivery.AuxpCred02
- dbo.LMDelivery.AuxpCred03 - dbo.LMDelivery.AuxpCred04 - dbo.LMDelivery.AuxpCred05 - dbo.LMDelivery.AuxpCred06 - dbo.LMDelivery.AuxpCred07 - dbo.LMDelivery.AuxpCred08 - dbo.LMDelivery.AuxpCred09 - dbo.LMDelivery.AuxpCred10
- dbo.LMDelivery.AuxpCred11 - dbo.LMDelivery.AuxpCred12 + dbo.LMDelivery.AuxmChrg01 + dbo.LMDelivery.AuxmChrg02 + dbo.LMDelivery.AuxmChrg03 + dbo.LMDelivery.AuxmChrg04 + dbo.LMDelivery.AuxmChrg05 + dbo.LMDelivery.AuxmChrg06
+ dbo.LMDelivery.AuxmChrg07 + dbo.LMDelivery.AuxmChrg08 - dbo.LMDelivery.AuxmCred01 - dbo.LMDelivery.AuxmCred02 - dbo.LMDelivery.AuxmCred03 - dbo.LMDelivery.AuxmCred04 - dbo.LMDelivery.AuxmCred05 - dbo.LMDelivery.AuxmCred06
- dbo.LMDelivery.AuxmCred07 - dbo.LMDelivery.AuxmCred08) AS Revenue
FROM dbo.LMDelivery INNER JOIN
dbo.LMCustomer ON dbo.LMDelivery.ShipCustRcID = dbo.LMCustomer.RcID INNER JOIN
dbo.LMContract ON dbo.LMDelivery.ContRcID = dbo.LMContract.RcID
WHERE (dbo.LMDelivery.UsefCanc = 0) AND (dbo.LMContract.StrtDate >= '2018-01-01') AND (dbo.LMDelivery.LdryDelvDate >= '2018-01-01')
GROUP BY dbo.LMCustomer.RcID, dbo.LMCustomer.Name, COALESCE (DATEPART(week, dbo.LMDelivery.LdryDelvDate), 0)
Your query is limited to only show weeks where there is a delivery (and thus, presumably, revenue) by the use of the LMDelivery table in the FROM clause.
If you wished to see a list of all customers, all weeks, and whatever delivery information is necessary, then you're going to need to start with a list of all customers and all weeks.
Assuming SQL Server, you could use a CTE to come up with a list of the weeks that have been in the year so far, connect that with your customer list, then seek out any relevant deliveries and their associated contracts. Something like the following:
;WITH
e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY e1.n) AS n FROM e1 CROSS JOIN e1 AS b), -- 10*10
num(WeekOfYear) AS
(
SELECT
n - 1
FROM e2
WHERE n <= DATEPART(WEEK, GETDATE()) + 1
)
SELECT dbo.LMCustomer.Name,
SUM(dbo.LMDelivery.LdryCensChrg + dbo.LMDelivery.LdryWghtChrg + dbo.LMDelivery.LdryPiecChrg - dbo.LMDelivery.RetnWghtCred - dbo.LMDelivery.RetnPiecCred - dbo.LMDelivery.VrncChrg + dbo.LMDelivery.LdryDelvChrg +
dbo.LMDelivery.PrchChrg + dbo.LMDelivery.LdryPcntChrg + dbo.LMDelivery.AuxpChrg01 + dbo.LMDelivery.AuxpChrg02 + dbo.LMDelivery.AuxpChrg03 + dbo.LMDelivery.AuxpChrg04 + dbo.LMDelivery.AuxpChrg05 + dbo.LMDelivery.AuxpChrg06
+ dbo.LMDelivery.AuxpChrg07 + dbo.LMDelivery.AuxpChrg08 + dbo.LMDelivery.AuxpChrg09 + dbo.LMDelivery.AuxpChrg10 + dbo.LMDelivery.AuxpChrg11 + dbo.LMDelivery.AuxpChrg12 - dbo.LMDelivery.AuxpCred01 - dbo.LMDelivery.AuxpCred02
- dbo.LMDelivery.AuxpCred03 - dbo.LMDelivery.AuxpCred04 - dbo.LMDelivery.AuxpCred05 - dbo.LMDelivery.AuxpCred06 - dbo.LMDelivery.AuxpCred07 - dbo.LMDelivery.AuxpCred08 - dbo.LMDelivery.AuxpCred09 - dbo.LMDelivery.AuxpCred10
- dbo.LMDelivery.AuxpCred11 - dbo.LMDelivery.AuxpCred12 + dbo.LMDelivery.AuxmChrg01 + dbo.LMDelivery.AuxmChrg02 + dbo.LMDelivery.AuxmChrg03 + dbo.LMDelivery.AuxmChrg04 + dbo.LMDelivery.AuxmChrg05 + dbo.LMDelivery.AuxmChrg06
+ dbo.LMDelivery.AuxmChrg07 + dbo.LMDelivery.AuxmChrg08 - dbo.LMDelivery.AuxmCred01 - dbo.LMDelivery.AuxmCred02 - dbo.LMDelivery.AuxmCred03 - dbo.LMDelivery.AuxmCred04 - dbo.LMDelivery.AuxmCred05 - dbo.LMDelivery.AuxmCred06
- dbo.LMDelivery.AuxmCred07 - dbo.LMDelivery.AuxmCred08) AS Revenue
FROM
dbo.LMCustomer INNER JOIN
num ON 1=1 LEFT JOIN
dbo.LMDelivery ON dbo.LMDelivery.ShipCustRcID = dbo.LMCustomer.RcID LEFT JOIN
dbo.LMContract ON dbo.LMDelivery.ContRcID = dbo.LMContract.RcID
WHERE LMDelivery.ShipCustRcID IS NULL OR (
(dbo.LMDelivery.UsefCanc = 0) AND (dbo.LMContract.StrtDate >= '2018-01-01') AND (dbo.LMDelivery.LdryDelvDate >= '2018-01-01')
AND COALESCE (DATEPART(week, LMDelivery.LdryDelvDate), 0) = num.WeekOfYear
)
GROUP BY dbo.LMCustomer.RcID, dbo.LMCustomer.NAME, num.WeekOfYear
Related
I am a little bit confusing and have no idea how to solve this problem. I have column in table Quantity which store Time value.
I want to create a following story. If I have for example
Quantity
8:00
8:00
It needs to SUM() this two and in output I need to get 16 HOURS
Second think, it needs to take last two number :00 and add to HOURS.
This is what I do so far
SELECT
(SUM(SUBSTR(A.Quantity, ':', 1)) + TRUNC((SUM(SUBSTR(A.Quantity, ':', -1)) / 60),0)), ':' ,
MOD(SUM(SUBSTR(A.Quantity, ':' , -1)), 60)
AS TOTAL_SUM FROM (
SELECT
ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM
ata
INNER JOIN
weekly_report
ON
weekly_report.ataId = ata.ATAID
INNER JOIN
ata_articles ataAW
ON
ataAW.wrId = weekly_report.id
WHERE
ata.ATAID = 10987
AND
ataAW.type = 1
OR
ataAW.type = 2
OR
ataAW.type = 3
AND
(weekly_report.status != 3 AND weekly_report.status != 4)
AND
(
weekly_report.year < (SELECT year FROM weekly_report WHERE id = 89)
OR
(
weekly_report.year <= (SELECT year FROM weekly_report WHERE id = 89)
AND
weekly_report.week <= (SELECT week FROM weekly_report WHERE id = 89)
)
)
) A
group by A.AtaId
So far better explanation, when I run first part of query I need to get something like
SELECT
CONCAT(
-- extract hours froAm time and add minutes converted to hours
(SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
-- , ':',
-- extract minutes from time and find reminder (modulo)*/
-- LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
) AS W_TOTAL_SUM
FROM
ata_articles aa
INNER JOIN
weekly_report wr
ON
aa.wrId = wr.id
WHERE
aa.wrId = 69
AND
aa.type = 1
TOTAL_SUM
16
And when I run second part
SELECT
CONCAT(
-- extract hours froAm time and add minutes converted to hours
-- (SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
-- , ':',
-- extract minutes from time and find reminder (modulo)*/
LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
) AS W_TOTAL_SUM
FROM
ata_articles aa
INNER JOIN
weekly_report wr
ON
aa.wrId = wr.id
WHERE
aa.wrId = 69
AND
aa.type = 1
I get output
TOTAL_SUM
00
Can someone guide me and tell me how to solve this issue since I try every solution but unfortunetlly doesn't work. And here is what I try so far, but I always get message
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number
SELECT
(SUM(SUBSTR(A.Quantity, ':', 1)) + TRUNC((SUM(SUBSTR(A.Quantity, ':', -1)) / 60),0)), ':' ,
MOD(SUM(SUBSTR(A.Quantity, ':' , -1)), 60)
AS TOTAL_SUM FROM (
SELECT
ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM
ata
INNER JOIN
weekly_report
ON
weekly_report.ataId = ata.ATAID
INNER JOIN
ata_articles ataAW
ON
ataAW.wrId = weekly_report.id
WHERE
ata.ATAID = 10987
AND
ataAW.type = 1
OR
ataAW.type = 2
OR
ataAW.type = 3
AND
(weekly_report.status != 3 AND weekly_report.status != 4)
AND
(
weekly_report.year < (SELECT year FROM weekly_report WHERE id = 89)
OR
(
weekly_report.year <= (SELECT year FROM weekly_report WHERE id = 89)
AND
weekly_report.week <= (SELECT week FROM weekly_report WHERE id = 89)
)
)
) A
group by A.AtaId
UPDATE
I get output error message
ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
Error at Line: 267 Column: 19
SELECT ( EXTRACT( DAY FROM duration ) * 24 + EXTRACT( HOUR FROM duration ) )
|| ':'
|| TO_CHAR( EXTRACT( MINUTE FROM DURATION ), 'FM00' )
|| ' HOURS' AS duration
FROM (
SELECT NUMTODSINTERVAL(SUM( SUBSTR( quantity, 1, INSTR( quantity, ':' ) - 1 ) ),'HOUR')
+ NUMTODSINTERVAL(SUM( SUBSTR( quantity, INSTR( quantity, ':' ) + 1 ) ), 'MINUTE' )
AS duration
FROM (
SELECT ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM ata
INNER JOIN weekly_report
ON weekly_report.ataId = ata.ATAID
INNER JOIN ata_articles ataAW
ON ataAW.wrId = weekly_report.id
INNER JOIN (SELECT week, year FROM weekly_report WHERE id = 89 ) b
ON ( weekly_report.year < b.year OR ( weekly_report.year = b.year AND weekly_report.week <= b.week ))
WHERE ata.ATAID = 10987
AND ataAW.type IN ( 1, 2, 3 )
AND weekly_report.status NOT IN ( 3, 4 )
))
group by A.AtaId
Here is what I get as output when I execute following code
DURATION
:HOURS
If you have the (slightly more complicated) sample data:
CREATE TABLE table_name ( Quantity ) AS
SELECT '8:00' FROM DUAL UNION ALL
SELECT '7:30' FROM DUAL UNION ALL
SELECT '0:30' FROM DUAL;
Then you can use string functions to get the hour and minute parts and sum those and then convert the totals to an interval (so you don't end up with 15:60 HOURS) and then format the output:
SELECT ( EXTRACT( DAY FROM duration ) * 24
+ EXTRACT( HOUR FROM duration )
)
|| ':'
|| TO_CHAR( EXTRACT( MINUTE FROM DURATION ), 'FM00' )
|| ' HOURS' AS duration
FROM (
SELECT NUMTODSINTERVAL(
SUM( SUBSTR( quantity, 1, INSTR( quantity, ':' ) - 1 ) ),
'HOUR'
)
+
NUMTODSINTERVAL(
SUM( SUBSTR( quantity, INSTR( quantity, ':' ) + 1 ) ),
'MINUTE'
) AS duration
FROM table_name
);
Which outputs:
| DURATION |
| :---------- |
| 16:00 HOURS |
db<>fiddle here
Hey need help with finding maximum average weight of three columnes (attempt1, attempt2 and attempt3 and showing which exercise they belong to and what date they occurred.
Atm, the results of the below query outputs, all exercises, all dates they occurred on and all the avg weights. I want it to select the max avg weight, the exercise it belongs to and date it occurred. Attached is the result of the query and ive highlighted what I want to be the output.
Result of query
SELECT e.exercise_description
, occ.occ_date, (COALESCE(OE.ATTEMPT1, 0)
+ COALESCE(OE.ATTEMPT2, 0)
+ COALESCE(OE.ATTEMPT3, 0))
/(3 -(COALESCE(OE.ATTEMPT1 - OE.ATTEMPT1, 1)
+ COALESCE(OE.ATTEMPT2 - OE.ATTEMPT2, 1)
+ COALESCE(OE.ATTEMPT3 - OE.ATTEMPT3, 1))
) AS row_avg
FROM EXERCISE E INNER JOIN Occurrence_Exercise OE
ON E.EXERCISEID=OE.EXERCISEID
INNER JOIN OCCURRENCE OCC ON OE.OCCURRENCEID=OCC.OCCURRENCEID;
You can just use window row_number() function to get the biggest avg one
SELECT e.exercise_description
, occ.occ_date
FROM
(SELECT oe.exerciseid
, oe.occurrenceid
, ROW_NUMBER() OVER(ORDER BY (COALESCE(oe.attempt1, 0) + COALESCE(oe.attempt2, 0)+ COALESCE(oe.attempt3, 0))
/ (NVL2(oe.attempt1, 1, 0) + NVL2(oe.attempt2, 1, 0) + NVL2(oe.attempt3, 1, 0))
) AS rn
FROM Occurrence_Exercise oe
) srt
INNER JOIN exercise e
ON srt.exerciseid=e.exerciseid
INNER JOIN occurrence occ
ON srt.occurrenceid=occ.occurrenceid
WHERE srt.rn = 1
I am new to SQL Server. I have a SQL query where I performed an union all, the 2 individual queries have group by.
select top 5
Starttime, convert(date,row_date) as Date,
sum(acdcalls + abncalls) [Offered],
sum(acdcalls) [Handled],
sum(abncalls) [Abandoned],
sum(acdcalls1 + acdcalls2 + acdcalls3 + acdcalls4 + acdcalls5) [Answered within SLA],
case
when sum(acdcalls) != 0
then cast((sum(acdcalls1 + acdcalls2 + acdcalls3 + acdcalls4 + acdcalls5)) * 1.0 / sum((acdcalls)) * 1.0 * 100 as decimal(10, 2))
else 0
end as [SLA in %]
from
db1
where
row_date = getdate()
group by
Starttime, row_Date
union all
select top 5
Starttime, convert(date,row_date) as Date,
sum(acdcalls + abncalls) [Offered],
sum(acdcalls) [Handled],
sum(abncalls) [Abandoned],
sum(acdcalls1 + acdcalls2 + acdcalls3 + acdcalls4 + acdcalls5) [Answered within SLA],
case
when sum(acdcalls) != 0
then cast((sum(acdcalls1 + acdcalls2 + acdcalls3 + acdcalls4 + acdcalls5)) * 1.0 / sum((acdcalls)) * 1.0 * 100 as decimal(10, 2))
else 0
end as [SLA in %]
from
db2
where
row_date = getdate()
group by
Starttime, row_Date
Starttime column has common values. I want to do group by Starttime for the result. How can I do that? Any help would be much appreciated
You need to do the union first, then aggregate. The following example uses a subquery, but you can use a temp table instead if you prefer:
Select StartTime, Row_Date, sum(acdcalls+abncalls)...[other sums here]
From (
select * from db1
union all
select * from db2
) a
group by StartTime, RowDate
You can still have your where clauses and your specific columns in the subquery if necessary (the example above will only work if db1 and db2 have the same columns in the same order - otherwise you will need to specify your columns). I am not sure why you want to group by Row_Date if you are limiting both of your selects to Row_Date = GetDate(), though.
select
j.name as 'JobName',
run_date,
run_time,
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
h.run_duration,
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60)
as 'RunDurationMinutes'
From msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h
ON j.job_id = h.job_id
where j.enabled = 1
AND
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60) > 1
The above SQL query will fetch list of a all jobs that takes more then a minute.
But it give a huge list, i dont want that all.
I just want last 2 run of every jobs.
I tried using top 2 and order by desc but it does not list all the jobs in the list.
I just want last 2 run of every job.
Any suggestions.?
Look at ROW_NUMER() ranging function:
select * from (
select
j.name as 'JobName',
run_date,
run_time,
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
h.run_duration,
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60)
as 'RunDurationMinutes',
ROW_NUMBER() OVER(PARTITION BY j.name ORDER BY msdb.dbo.agent_datetime(run_date, run_time) DESC) NROW
From msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h
ON j.job_id = h.job_id
where j.enabled = 1
AND
((run_duration/10000*3600 + (run_duration/100)%100*60 + run_duration%100 + 31 ) / 60) > 1
) t where nrow < 3
To make things clear I have done:
Add new column to your query:
ROW_NUMBER() OVER(PARTITION BY j.name ORDER BY msdb.dbo.agent_datetime(run_date, run_time) DESC) NROW
This column group by all the records by j.name field and number each group by 'RunDateTime' field.
Now we need to get all the records where NROW == 1 or NROW == 2. I have created subquery (not sure it is a best solution) and and WHERE condition
select * from ( ... ) t where nrow < 3
Try this
SELECT
r.session_id, r.start_time,
TotalElapsedTime_ms = r.total_elapsed_time
, r.[status]
, r.command
, DatabaseName = DB_Name(r.database_id)
, r.wait_type
, r.last_wait_type
, r.wait_resource
, r.cpu_time
, r.reads
, r.writes
, r.logical_reads
, t.[text] AS [executing batch]
, SUBSTRING(
t.[text], r.statement_start_offset / 2,
( CASE WHEN r.statement_end_offset = -1 THEN DATALENGTH (t.[text])
ELSE r.statement_end_offset
END - r.statement_start_offset ) / 2
) AS [executing statement]
, p.query_plan
FROM
sys.dm_exec_requests r
CROSS APPLY
sys.dm_exec_sql_text(r.sql_handle) AS t
CROSS APPLY
sys.dm_exec_query_plan(r.plan_handle) AS p
ORDER BY
r.total_elapsed_time DESC;
Is it possible to write union select queries like the following more succintly?
select
id,
1,
(1 + #defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - #defCapDown) * (p.Value - p.Premium),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - #defCapUp) * (p.Value - p.Premium),
#nextYear
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 + #defCapDown) * (p.Value + p.Premium),
#nextYear
from Products p
The statement selects four rows for each row in the Products table. The only thing varying is the formula used to calculate the values for column two and tree. I think there should be a way in sql to write the above without so much ugly code duplication. If only functions were first class objects and sql allowed lambda expressions...
Richard's solution down below is perfect, works very well for the example provided. But I had two typos in the orignal example which makes the problem somewhat tougher:
select
id,
1,
(1 + #defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - #defCapDown) * (p.Value - p.Payout),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - #defCapUp) * (p.Value - p.Premium),
#nextYear
from Products p
union
select
id,
case when p.Paydate <= getdate() then 1 else 0 end,
(1 + #defCapDown) * (p.Value + p.Payout),
#nextYear
from Products p
The big problem is the case expression in which the comparison operator differs. My problem is that it is very hard to "neatly" handle those cases. What if there were a third case where the comparison was p.Paydate = getdate() for example?
(Not sure how lambda expressions would have helped you)
select
id,
case when p.Paydate > X.CompareDate then 1 else 0 end,
(1 + Cap) * (p.Value + ModF * p.Premium),
#nextYear
from Products p
cross join (
select #defCapUp Cap, Cast(0 as datetime) CompareDate, 1 Modf union all
select -#defCapDown, 0, -1 union all
select -#defCapUp, GETDATE(), -1 union all
select #defCapDown, GETDATE(), 1
) X
BTW, you should have been using UNION ALL, not UNION.
If the order doesn't matter, you could use WHERE.
SELECT id, field2, field3, field4
FROM Products p
WHERE (
field4 = getdate() AND field2=1 AND
(
field3=(1 + #defCapUp) * (p.Value + p.Premium) OR
field3=(1 - #defCapDown) * (p.Value - p.Premium)
)
)
OR
(
field4=#nextYear AND field2=(case when p.Paydate > getdate() then 1 else 0 end) AND
(
field3=(1 - #defCapUp) * (p.Value - p.Premium) OR
field3=(1 + #defCapDown) * (p.Value + p.Premium)
)
)