SQL query to select percentage of total
sql, sql-server
Solution
WITH cte
AS (SELECT storeid,
numemployees,
( numemployees * 100 ) / SUM(numemployees) OVER (PARTITION BY 1)
AS
percentofstores
FROM stores)
SELECT *
FROM cte
WHERE percentofstores >= 30
ORDER BY numemployees desc
Working Demo
Alternative that doesn't use SUM/OVER
SELECT s.storeid, s.numemployees
FROM (SELECT SUM(numemployees) AS [tots]
FROM stores) AS t,
stores s
WHERE CAST(numemployees AS DECIMAL(15, 5)) / tots >= .3
ORDER BY s.numemployees desc
Working Demo
Note that in the second version I decided not to multiply by 100 before dividing. This requires a cast to decimal otherwise it would be implicitly converted to a int resulting in no records returned
Also I'm not completely clear that you want this, but you can add `TOP 1` to both queries and it will limit the results to just the one with the greatest # of stores with more than 30%
UPDATE
Based on your comments it sounds to paraphrase Kevin
You want the rows, starting at the store with the most employees and working down until you have at least 30 %
This is difficult because it requires a running percentage and its a bin packing problem however this does work. Note I've included two other test cases (where the percent exactly equals and its just over the top two combined)
Working Demo
DECLARE @percent DECIMAL (20, 16)
SET @percent = 0.3
--Other test values
--SET @percent = 0.6992547128452433
--SET @percent = 0.6992547128452434
;WITH sums
AS (SELECT DISTINCT s.storeid,
s.numemployees,
s.numemployees + Coalesce(SUM(s2.numemployees) OVER (
PARTITION
BY
s.numemployees), 0)
runningsum
FROM stores s
LEFT JOIN stores s2
ON s.numemployees < s2.numemployees),
percents
AS (SELECT storeid,
numemployees,
runningsum,
CAST(runningsum AS DECIMAL(15, 5)) / tots.total
running_percent,
Row_number() OVER (ORDER BY runningsum, storeid ) rn
FROM sums,
(SELECT SUM(numemployees) total
FROM stores) AS tots)
SELECT p.storeID,
p.numemployees,
p.running_percent,
p.running_percent,
p.rn
FROM percents p
CROSS JOIN (SELECT MAX(rn) rn
FROM percents
WHERE running_percent = @percent) exactpercent
LEFT JOIN (SELECT MAX(rn) rn
FROM percents
WHERE running_percent <= @percent) underpercent
ON p.rn <= underpercent.rn
OR ( exactpercent.rn IS NULL
AND p.rn <= underpercent.rn + 1 )
WHERE
underpercent.rn is not null or p.rn = 1
Problem
I have a MSSQL table stores that has the following columns in a table: ``` Storeid, NumEmployees 1 125 2 154 3 10 4 698 5 54 6 98 7 87 8 100 9 58 10 897 ``` Can someone help me with the SQL query to produce the top stores(storeID) that has 30% of the total emplyees(NumEmployees)?