Counting in a sql query - sql

So I'm having a table like
Now I need to get this packed into a datagridview when a choice is made in a combobox filled with the uv ='owner'.
If I make a choice of the uv eg MG. I get a list of all his files/dosno he worked in and the times he spend working on the file.
I do this with this query :
SELECT kbpres.uv,
dbo.doss.dosno,
SUM(dbo.kbpres.uur) AS somuur,
SUM(dbo.kbpres.minuut) AS somminuut,
CAST (( SUM(dbo.kbpres.uur) + SUM(dbo.kbpres.minuut) / 60 ) AS VARCHAR(4)
) +
'u ' + CAST (( SUM(dbo.kbpres.minuut) % 60 ) AS VARCHAR(2)) + 'm' AS
[derivedColumn],
doss.behdr
FROM dbo.kbpres
INNER JOIN dbo.doss
ON dbo.kbpres.ino = dbo.doss.ino
WHERE ( dbo.kbpres.uv LIKE #cboBeheerder )
GROUP BY kbpres.uv,
dbo.doss.dosno,
doss.behdr
(Allthough I would only like to group by UV, and have to add the dosno and behdr as well ??)
The problem is now, how can I count the correct cost, as it is per record different.
for MG it would be :
10 * 60 for dosno 88888
20 * 76 for 66666
60*10 + (28hours+10minutes * 10) + 10*2 for 12345
Any idea if this is even possible ??

SELECT dosno,
SUM(uur)*60 + SUM(minuut) AS Time,
(SUM(uur)*60 + SUM(minuut)) * cost AS TotalCost
FROM dbo.kbpres k
INNER JOIN dbo.doss d ON k.ino = d.ino
GROUP BY dosno,k.ino,d.ino,cost
WHERE k.uv = 2
As cost seems to be a function of uv and dosno try
SELECT dosno,SUM(Time) AS Time,SUM(TotalCost) AS TotalCost FROM
(
SELECT dosno,
uur*60 + minuut AS Time,
(uur*60 + minuut) * cost AS TotalCost
FROM dbo.kbpres k
INNER JOIN dbo.doss d ON k.ino = d.ino
GROUP BY dosno,k.ino,d.ino,cost
WHERE k.uv = 2
) t
GROUP BY dosno

Related

How add up values from multiple SQL columns based on occurrances

I need select values from a table and returns the total hours for all categories and their occurrences. The challenge is that there are different totals for each occurrence.
My query:
SELECT c.Category,
c.HrsFirstOccur,
c.HrsAddlOccur,
COUNT(*) AS Occurrences
FROM dbo.Categories sc
INNER JOIN dbo.Categories c
ON sc.CategoryID = c.CategoryID
INNER JOIN dbo.OrderHistory oh
ON sc.GONumber = oh.OrderNumber
AND sc.Item = oh.ItemNumber
WHERE sc.BusinessGroupID = 1
AND oh.OrderNumber = 500
AND oh.ItemNumber = '100'
GROUP BY c.Category, c.HrsFirstOccur, c.HrsAddlOccur
returns the following results:
Category
HrsFirstOccur
HrsAddlOccur
Occurrences
Inertia
24
16
2
Lights
1
0.5
4
Labor
10
0
1
The total is calculated based on the number of occurrences. The first one is totaled then for each additional occurrence, the HrsAddlOccur is used.
My final result should be (24 + 16) + (1 + 0.5 + 0.5 + 0.5) + 10 for a grand total of 52.5.
How do I loop and process the results to total this up?
The total is calculated based on the number of occurrences. The first one is totaled then for each additional occurrence, the HrsAddlOccur is used.
SQL databases understand arithmetic. You can perform the computation on each row. As I understand, the logic you want is:
SELECT
c.Category,
c.HrsFirstOccur,
c.HrsAddlOccur,
COUNT(*) AS Occurrences,
c.HrsFirstOccur + ( COUNT(*) - 1 ) * HrsAddlOccur As Total
FROM ... < rest of your query > ..
Later on you can aggregate the whole resultset to get the grand total:
SELECT SUM(Total) GrandTotal
FROM (
... < above query > ..
) t
you can sum them simply up
WITH CTE as(SELECT c.Category,
c.HrsFirstOccur,
c.HrsAddlOccur,
COUNT(*) AS Occurrences
FROM dbo.Categories sc
INNER JOIN dbo.Categories c ON sc.CategoryID = c.CategoryID
INNER JOIN dbo.OrderHistory oh ON sc.GONumber = oh.OrderNumber
AND sc.Item = oh.ItemNumber
WHERE sc.BusinessGroupID = 1
AND oh.OrderNumber = 500
AND oh.ItemNumber = '100')
SELECT SUM(HrsFirstOccur + (CAST((Occurrences -1) AS DECIMAL(8,2)) * HrsAddlOccur)) as total FROM CTE
it would do it like the example
CREATE TABLE CTE
([Category] varchar(7), [HrsFirstOccur] int, [HrsAddlOccur] DECIMAL(8,2), [Occurrences] int)
;
INSERT INTO CTE
([Category], [HrsFirstOccur], [HrsAddlOccur], [Occurrences])
VALUES
('Inertia', 24, 16, 2),
('Lights', 1, 0.5, 4),
('Labor', 10, 0, 1)
;
3 rows affected
SELECT SUM(HrsFirstOccur + (CAST((Occurrences -1) AS DECIMAL(8,2)) * HrsAddlOccur)) as total
FROM CTE
total
52.5000
fiddle

How do i get result?

I need SUM of this result:
SELECT
ROUND(
(invoicesitems.pscost / invoicesitems.inmedunit -
AVG(ISNULL(mainexstock.peacecost,0)) / invoicesitems.inmedunit), 2)
*
CASE WHEN units.unitqty=3 THEN (invoicesitems.bigqty *
invoicesitems.inbigunit * invoicesitems.inmedunit) +
(invoicesitems.medqty * invoicesitems.inmedunit) +
invoicesitems.smallqty
ELSE (invoicesitems.bigqty * invoicesitems.inmedunit)
+ invoicesitems.smallqty
END AS PROFITS
FROM invoicesitems
INNER JOIN mainexstock ON mainexstock.pid = invoicesitems.pid
INNER JOIN units ON units.[uid] = invoicesitems.punits
WHERE invoicesitems.bid = 'B-0480580'
GROUP BY
invoicesitems.pid, invoicesitems.inbigunit,
invoicesitems.inmedunit, invoicesitems.bigqty,
invoicesitems.medqty, invoicesitems.smallqty,
invoicesitems.pscost, units.unitqty
You can use it as a CTE and get the sum. For example:
with a as (
-- your big query here
)
select sum(profits) as profits from a;

Summary table with row/column totals using SQL pivot

I need help with SQL for generating pivot table with row/column totals calculated ..I have 2 tables as given below
Table ProbCat
==============
probcat | probdesc
1 minor
2 high
3 showstopper
Table ProbSummary
===================
prodcat | noofproblems | stage
1 5 Dev
2 1 Dev
3 6 QA
3 6 Prod
and I would like to generate a pivot table with row/column total percentages as shown below. I have tried combination of 'pivot' and 'group by' but could not get the row & column total accurately
Probelm Summary view:
ProbCategory CategoryDesc Dev Qa Prod Total(%)
______________________________________________________
1 Minor 5 0 0 5(100*(5/18))
2 High 1 0 0 1(100*(1/18))
3 Showstopper 0 6 6 12(100*(6/18))
Total NA 6(%) 6(%) 6(%)
Just like others mentioned, your summary/total calculation should be done on the presentation layer. But here is my attempt to getting your output minus the last summary line:
;WITH Q1
AS (
SELECT pvt.probcat
,pvt.probdesc
,ISNULL(pvt.[Dev], 0) AS 'Dev'
,ISNULL(pvt.[QA], 0) AS 'QA'
,ISNULL(pvt.[Prod], 0) AS 'Prod'
FROM (
SELECT pc.probcat
,pc.probdesc
,ps.noofproblems
,ps.stage
FROM Probcat pc
LEFT JOIN ProbSummary ps ON pc.probcat = ps.probcat
) t
PIVOT(max(noofproblems) FOR stage IN (
[Dev]
,[QA]
,[Prod]
)) pvt
),
q2 as
(SELECT q1.*
,sum(q1.Dev + q1.QA + q1.Prod) AS Total
FROM q1
GROUP BY q1.probcat
,q1.probdesc
,q1.Dev
,q1.QA
,q1.Prod
)
select q2.probcat
,q2.probdesc
,q2.Dev
,q2.QA
,q2.Prod
,cast(q2.Total as varchar(10)) + ' (' +
cast(cast((cast(q2.Total as decimal(5,2))/cast(d.CrossSum as decimal(5,2)))*100
as decimal(5,2)) as varchar(10))
+ '% )' as FinalTotal
from q2
CROSS APPLY (
SELECT sum(q1.Dev + q1.QA + q1.Prod) AS CrossSum
FROM q1
) d
ORDER BY q2.probcat
SQL Fiddle Demo
with x as
(select p.probcat as probcategory, p.probdesc as categotydesc,
case when s.stage = 'Dev' and s.noofproblems > 0 then s.noofproblems else 0 end as Dev,
case when s.stage = 'QA' and s.noofproblems > 0 then s.noofproblems else 0 end as QA,
case when s.stage = 'Prod' and s.noofproblems > 0 then s.noofproblems else 0 end as Prod
from Probcat p join Probsummary s on p.probcat = s.prodcat)
select probcategory,categotydesc,Dev,QA,Prod, Dev+QA+Prod as Total
from x
this should give what you need except the Total row at the bottom.
Here's a PIVOT query you can work with.. your example has prodcat in one table and probcat in the other.. not sure if that was typo in second table so i just with with probcat for both. should be easy to fix it it gives you an error
;
WITH ProbCatSummary AS
(
SELECT pc.probcat,
pc.probdesc,
SUM(ps.noofproblems) AS noofproblems
FROM ProbCat pc
JOIN ProbSummary ps ON pc.probcat = ps.probcat
GROUP BY pc.probcat,
pc.probdesc
)
SELECT p.*,
[Total (%)] = CONVERT(VARCHAR,[Dev] + [QA] + [Prod])
+ ' (' + CONVERT(VARCHAR,
CAST(ROUND((([Dev] + [QA] + [Prod]) * 100.0 / SUM(ps.noofproblems) OVER()),2) AS DECIMAL(8,2))
)
+ ')'
FROM (
SELECT probcat, probdesc, ISNULL([Dev],0)[Dev], ISNULL([QA],0)[QA], ISNULL([Prod],0)[Prod]
FROM (SELECT pc.probcat, probdesc, stage, noofproblems
FROM ProbCat pc
JOIN ProbSummary ps ON pc.probcat = ps.probcat) AS s
PIVOT (SUM(noofproblems) FOR stage IN ([Dev], [QA], [Prod])) AS p
) p JOIN ProbCatSummary ps ON p.probcat = ps.probcat

Need T-SQL Query find all possible ways

create table #sample (
product varchar(100),
Price float
)
insert into #sample values ('Pen',10)
insert into #sample values ('DVD',29)
insert into #sample values ('Pendrive',45)
insert into #sample values ('Mouse',12.5)
insert into #sample values ('TV',49)
select * from #sample
Consider this situation ...
I have 1000$, I want to buy something listed above.
I want to spend the entire amount
So I need a query which gives how much units in all products will cost 1000$
Any help ?
The problem you are referring to is also known as the knapsack problem. There's a range of algorithms you can use to solve this. The most well known is dynamic programming, it requires that the weights are integer numbers, so you'd have to measure in cents. None of them are easy to implement in t-sql.
I actually found a link to someone's implementation in sql server: http://sqlinthewild.co.za/index.php/2011/02/22/and-now-for-a-completely-inappropriate-use-of-sql-server/
Notice the title, they too find it an inappropriate use of a database.
I'd recommend that you solve this in a different language.
It's possible to remove a lot of data by limiting the space for the current item to the money not already spent.
On my home system it takes between 2.6s and 2.8s to run.
On SQLFiddle the first few runs can take more, then it stabilize around 1.8s.
WITH Unit(N) AS (
SELECT N
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) t(N)
), Counter(N) AS (
SELECT u.n + 10*te.n + 100*hu.n
FROM Unit u CROSS JOIN Unit te CROSS JOIN Unit hu
WHERE u.n + 10*te.n + 100*hu.n <= (SELECT 1000 / Min(Price) FROM Sample))
SELECT N INTO #Counter FROM Counter;
WITH Products AS (
SELECT [Pen], [DVD], [PenDrive], [Mouse], [TV]
FROM (SELECT product, price FROM sample) s PIVOT
(MAX(price) FOR product IN ([Pen], [DVD], [PenDrive], [Mouse], [TV])) p
)
SELECT cP.N Pen, cD.N DVD, cPe.N PenDrive, cM.N Mouse
, CAST((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N - p.Mouse * cM.N) / p.TV as INT) TV
, Money = p.pen * cP.N + p.DVD * cD.N + p.PenDrive * cPe.N
+ p.Mouse * cM.N
+ p.TV * CAST((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N - p.Mouse * cM.N) / p.TV as INT)
From Products p
LEFT Join #Counter cP ON cP.N <= (1000 / p.Pen)
LEFT Join #Counter cD ON cD.N <= ((1000 - p.pen * cP.N) / p.DVD)
LEFT Join #Counter cPe
ON cPe.N <= ((1000 - p.pen * cP.N - p.DVD * cD.N) / p.PenDrive)
LEFT Join #Counter cM
ON cM.N <= ((1000 - p.pen * cP.N - p.DVD * cD.N
- p.PenDrive * cPe.N) / p.Mouse)
WHERE p.pen * cP.N + p.DVD * cD.N
+ p.PenDrive * cPe.N + p.Mouse * cM.N
+ p.TV * CAST((1000 - p.pen * cP.N - p.DVD * cD.N - p.PenDrive * cPe.N
- p.Mouse * cM.N) / p.TV as INT) = 1000
What's changed
The #Counter is now a temp table, it's calculated only once
The various Product CTEs are gone, substituted by the sample table pivoted
The CROSS JOIN in the Products CTE are gone, they remain in the main select but four less CROSS JOIN is always good
The TOP is gone, the WHERE condition takes care of showing only the perfect solutions
In the main select we have now LEFT JOIN... nope they are still CROSS JOIN, the LEFT JOIN are used because the CROSS JOIN don't have the ON clause used to limit the number of rows
How it works
The products price unpivoted make it possible to get the products price by 'name' (column name).
The FROM block works like 4 indented FOR, where the (1000 - already spent) / price clauses, limit the counters only to the values that will not exceed the 1000$.
The last product is always calculated by difference (how many $ are still unspent / price), dropping a CROSS JOIN completely
SQLFiddle Demo with 1000$ as the total money.
With the data provided there are 3531 solution
Old Answer
If you want to have you server run for all the time of you lunch here is a dumb solution.
Mind you, this solution explore all the space of the problem so the performance will be, at best, crappy.
WITH Base(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)
, Unit(N) AS (
SELECT Row_Number() Over (ORDER BY (SELECT NULL)) - 1
FROM Base)
, Counter(N) AS (
SELECT u.n + 10*te.n + 100*hu.n + 1000*th.n
FROM Unit u
CROSS JOIN Unit te --tens
CROSS JOIN Unit hu --hundreds
CROSS JOIN Unit th --thousands
WHERE u.n + 10*te.n + 100*hu.n + 1000*th.n <= (SELECT 1000 / Min(Price)
FROM Sample))
, Pens AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Pen' AND N <= 1000 / Price)
, DVDs AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'DVD' AND N <= 1000 / Price)
, Pendrives AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Pendrive' AND N <= 1000 / Price)
, Mouses AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'Mouse' AND N <= 1000 / Price)
, TVs AS (
SELECT product, Price = price * N, Quantity = N
FROM sample CROSS JOIN Counter
WHERE product = 'TV' AND N <= 1000 / Price
)
SELECT TOP 10
Pen = p.Quantity
, DVD = d.Quantity
, Pendrive = pe.Quantity
, Mouse = m.Quantity
, TV = t.Quantity
, Price = p.Price + d.price + pe.price + m.price + t.price
FROM pens p
CROSS JOIN DVDs d
CROSS JOIN Pendrives pe
CROSS JOIN Mouses m
CROSS JOIN TVs t
WHERE p.Price + d.price + pe.price + m.price + t.price <= 1000
ORDER BY p.Price + d.price + pe.price + m.price + t.price DESC
SQLFiddle Demo with 100$ as the total money (it takes about 2 second to run)
SQLFiddle Demo with 200$ as the total money (it takes about 6 second to run)
A demo with 1000$ will probably result in a time-out
How this work
Base serve as base of Unit.
Unit count from 0 to 9
Counter use Unit to count from 0 to 9999, or the limit imposed from by the cheaper money you want to spend divided by the price of the cheaper item.
Every item has his CTE to calculate the price of that item for any number of times within your capital.
The product CTEs are cross joined to check every combination within the limit of the money.
The TOP 10 is here because there can be more then one combination where the exact amount of money is used.
That just to say that yes you can devise a solution in SQLServer, it's not even that difficult, but that doesn't mean that you should to it.
This is hard coded and has little flexiblity. Took my system 2 minutes to run. But might be helpful, sorry if it isn't. fnGenerate_Numbers is a table function that returns integers within the range of the parameters. Ways to do that.
DECLARE #Max INT,
#Pens money,
#Dvds money,
#Pendrives money,
#Mouses money,
#Tvs money
SELECT #Max = 1000,
#Pens = 10,
#Dvds = 29,
#Pendrives = 45,
#Mouses = 12.5,
#Tvs = 49
;WITH Results AS
(
SELECT p.n pens, d.n dvds, pd.n pendrives, m.n mouses, t.n tvs, tot.cost
FROM fnGenerate_Numbers(0, #Max/#Pens) p -- Pens
CROSS JOIN fnGenerate_Numbers(0, #Max/#Dvds) d -- DVDs
CROSS JOIN fnGenerate_Numbers(0, #Max/#Pendrives) pd -- Pendrives
CROSS JOIN fnGenerate_Numbers(0, #Max/#Mouses) m -- Mouses
CROSS JOIN fnGenerate_Numbers(0, #Max/#Tvs) t -- Tvs
CROSS APPLY (SELECT p.n * #Pens + d.n * #Dvds + pd.n * + #Pendrives + m.n * #Mouses + t.n * #Tvs cost) tot
WHERE tot.cost < #Max
), MaxResults AS
(
SELECT
MAX(pens) pens,
dvds,
pendrives,
mouses,
tvs
FROM Results
GROUP BY
dvds,
pendrives,
mouses,
tvs
)
SELECT mr.*, r.cost FROM MaxResults mr
INNER JOIN Results r ON mr.pens = r.pens
AND mr.dvds = r.dvds
AND mr.pendrives = r.pendrives
AND mr.mouses = r.mouses
AND mr.tvs = r.tvs
ORDER BY cost
If I understand the problem statement correctly, then it's a pretty simple query:
select product, price, floor(1000 / price) as QtyToBuy

SQL Puzzle - Why can't I join these two subqueries?

I'm stuck on a SQL query.
Consider the following table:
Table DG_GAME_ROUNDS
RoundId int
GameId int
RoundNumber int
Value varchar(20)
Guess varchar(20)
Answer varchar(20)
Correct bit
Minutes int
Seconds int
Milliseconds int
This table holds the results of game rounds. Now sometimes you can fat finger an answer to the game and wind up with a guess time of 35 or even 0 milliseconds. These answers skew the results of my game and I want to remove them.
I want to figure out the average guess time where the guess is at least 200 milliseconds long. So if a game had five rounds with guesses of 455, 400, 340, 30, 300. I want to ignore the 30 and average out the remaining four values and get an average guess time of 374. Without dropping the 30 the average guess time would be 305.
My problem is that I'm trying to join two subqueries and I'm getting an error message that there is a problem around the "on" statement. I think joining subqueries is allowed.
select vt.gameid, vt.totalms, vt.numofguesses, vt.correctguesses
from
(select gr.gameid
, sum((gr.seconds*1000) + gr.milliseconds) as totalms
, count(gr.roundid) as numofguesses
, sum(cast(gr.correct as int)) as correctguesses
from work_tables.dbo.dg_game_rounds gr (nolock)
group by gr.gameid
) vt
inner join (
select vtIII.gameid, vtIII.avgtime
from
(
select vtII.gameid, sum(vtII.avgms)/count(vtII.avgms) as avgtime
from (
select gr.gameid, gr.seconds * 1000 + gr.milliseconds as avgms
from dg_game_rounds gr (nolock)
where gr.seconds * 1000 + gr.milliseconds > 200
) vtII
group by vtII.gameid
) vtIII
on vtIII.gameid = vt.gameid
Because you're missing an ending ) (2nd to last line)
select vt.gameid, vt.totalms, vt.numofguesses, vt.correctguesses
from
(select gr.gameid
, sum((gr.seconds*1000) + gr.milliseconds) as totalms
, count(gr.roundid) as numofguesses
, sum(cast(gr.correct as int)) as correctguesses
from work_tables.dbo.dg_game_rounds gr (nolock)
group by gr.gameid
) vt
inner join (
select vtIII.gameid, vtIII.avgtime
from
(
select vtII.gameid, sum(vtII.avgms)/count(vtII.avgms) as avgtime
from (
select gr.gameid, gr.seconds * 1000 + gr.milliseconds as avgms
from dg_game_rounds gr (nolock)
where gr.seconds * 1000 + gr.milliseconds > 200
) vtII
group by vtII.gameid
) vtIII ) vtIII
on vtIII.gameid = vt.gameid
You haven't closed all your subqueries:
select vt.gameid, vt.totalms, vt.numofguesses, vt.correctguesses
from
(select gr.gameid
, sum((gr.seconds*1000) + gr.milliseconds) as totalms
, count(gr.roundid) as numofguesses
, sum(cast(gr.correct as int)) as correctguesses
from work_tables.dbo.dg_game_rounds gr (nolock)
group by gr.gameid
) vt
inner join (
select vtIII.gameid, vtIII.avgtime
from
(
select vtII.gameid, sum(vtII.avgms)/count(vtII.avgms) as avgtime
from (
select gr.gameid, gr.seconds * 1000 + gr.milliseconds as avgms
from dg_game_rounds gr (nolock)
where gr.seconds * 1000 + gr.milliseconds > 200
) vtII
group by vtII.gameid
) vtIII ) f
on f.gameid = vt.gameid
I added this: ) vtIII ) f
Count your parentheses.
inner join (
is never closed.