Get total count per ID change - tsql

how can I get a total count of sheets per change of sheet
example:
select sheetID,
..
from SomeTable
results look something like this:
sheetID
-----------
1000
1000
1000
1000
3000
3000
3000
so I want something like this:
select sheetID,
count(sheetID) as TotalsheetCount
from SomeTable
I just don't know how to break the count up per change of sheetID.
So I'd end up with this essentially:
sheetID TotalsheetCount
-------- -----------
1000 4
1000 4
1000 4
1000 4
3000 3
3000 3
3000 3
so 4 is because there are 4 1000s, 3 because there are 3 3000s. I am wanting to repeat the total count for that sheetID for each row, even though it's repeating, I want to provide that.
UPDATE, here's what I did per the replies but I'm getting way too many results now as compoared to the count where I did not add that partition count before
select MainTable.sheetID,
COUNT(SomeTable.sheetID)OVER(PARTITION BY SomeTable.sheetID) AS TotalSheetCount
table2.SomeField1,
table2.SomeField1
from MainTable
join (select distinct Sales.SalesKey from SomeLongTableName_Sales) sales on sales.SheetKey = MainTable.sheetKey
left outer join Site on MainTable.SiteKey = Site.SiteKey
join Calendar on sales.Date >= Calendar.StartDate
and sales.Date < Calendar.EndDate
group by SomeTable.sheetID
the joins and stuff is more realistic to my real query but formatted for this post to hide real field and table names.

You probably want to use a GROUP BY:
SELECT sheetID, COUNT(sheetID) AS TotalsheetCount
FROM dbo.SomeTable
GROUP BY sheetID
I am wanting to repeat the total count for that sheetID for each row,
even though it's repeating, I want to provide that
If you're using at least SQL-Server 2005, you can use a CTE with COUNT + OVER-clause, otherwise use a sub-query:
WITH CTE AS
(
SELECT sheetID,
COUNT(sheetID)OVER(PARTITION BY sheetID) AS TotalsheetCount
FROM SomeTable
)
SELECT sheetID, TotalsheetCount FROM CTE

Use the GROUP BY clause in a subquery to select the counts:
SELECT sheetID,
count(sheetID) as TotalsheetCount
FROM SomeTable
GROUP BY sheetID
This would make your whole query look like this:
SELECT t.sheetID,
counts.TotalsheetCount
FROM SomeTable t,
(SELECT sheetID, count(sheetID) as TotalsheetCount FROM SomeTable GROUP BY sheetID) counts
WHERE t.sheetID = counts.sheetID

It looks like you need a group-by expression:
select sheetID,
count(*) as TotalsheetCount
from SomeTable
group by sheetID
Is that it?
DC

Related

Postgres distinct query in two columns

I want to write a postgres query. For every distinct combination of (career-id and uid) I should return the entire row which has max time.
This is the sample data
id time career_id uid content
1 100 10000 5 Abc
2 300 6 7 xyz
3 200 10000 5 wxv
4 150 6 7 hgr
Ans:
id time career_id uid content
2 300 6 7 xyz
3 200 10000 5 wxv
this can be done using distinct on () in Postgres
select distinct on (career_id, uid) *
from the_table
order by career_id, uid, "time" desc;
You can use CTE's for this. Something like this should work:
WITH cte_max_value AS (
SELECT
career_id,
uid,
max("time") as max_time
FROM mytable
GROUP BY career_id, uid
)
SELECT DISTINCT t.*
FROM mytable AS t
INNER JOIN cte_max_value AS cmv
ON t.uid = cmv.uid AND t.career_id = cmv.career_id AND t.time = cmv.max_time
The CTE gives you all the unique combinations of career_id and uid with the relevant maximum time, the inner join then joins the entire rows into this. I'm using if you get two rows with the same maximum time for the same combination of career_id and uid you will get two rows returned.
If you don't want that you will need to find a strategy to resolve this.
Edit: Also the proposed solution by a_hrose_with_name's solution is far nicer and unless you need some level of compatibility with other servers (sadly syntax varies) you should use that instead.

SQL to select users into groups based on group percentage

To keep this simple, let's say I have a table with 100 records that include:
userId
pointsEarned
I would like to group these 100 records (or whatever the total is based on other criteria) into several groups as follows:
Group 1, 15% of total records
Group 2, 25% of total records
Group 3, 10% of total records
Group 4, 10% of total records
Group 5, 40% (remaining of total records, percentage doesn't really matter)
In addition to the above, there will be a minimum of 3 groups and a maximum of 5 groups with varying percentages that always totally 100%. If it makes it easier, the last group will always be the remainder not picked in the other groups.
I'd like to results to be as follows:
groupNbr
userId
pointsEarned
To do this sort of breakup, you need a way to rank the records so that you can decide which group they belong in. If you do not want to randomise the group allocation, and userId is contiguous number, then using userId would be sufficient. However, you probably can't guarantee that, so you need to create some sort of ranking, then use that to split your data into groups. Here is a simple example.
Declare #Total int
Set #Total = Select COUNT(*) from dataTable
Select case
when ranking <= 0.15 * #Total then 1
when ranking <= 0.4 * #Total then 2
when ranking <= 0.5 * #Total then 3
when ranking <= 0.6 * #Total then 4
else 5 end as groupNbr,
userId,
pointsEearned
FROM (Select userId, pointsEarned, ROW_NUMBER() OVER (ORDER BY userId) as ranking From dataTable) A
If you need to randomise which group data end up in, then you need to allocate a random number to each row first, and then rank them by that random number and then split as above.
If you need to make the splits more flexible, you could design a split table that has columns like minPercentage, maxPercentage, groupNbr, fill it with the splits and do something like this
Declare #Total int
Set #Total = Select COUNT(*) from dataTable
Select S.groupNbr
B.userId,
B.pointsEearned
FROM (Select ranking / #Total * 100 as rankPercent, userId, pointsEarned
FROM (Select userId, pointsEarned, ROW_NUMBER() OVER (ORDER BY userId) as ranking From dataTable) A
) B
inner join splitTable S on S.minPercentage <= rankPercent and S.maxPercentage >= rankPercent

how to values transfer to another column with two query

I have a query. this query is calculated percentage for every product. I created a virtual column on this query this columns name is 'yüzde'. After that, i want to transfer yüzde columns to another column in another table with update query if product ids are same.
I think I need to write a stored procedure. How can I do that?
SELECT [ProductVariantId] ,
count([ProductVariantId]) as bedensayısı,
count([ProductVariantId]) * 100.0 / (SELECT Top 1 Count(*) as Total
FROM [Live_ADL].[dbo].[_INV_ProductCombinationAttributes]
Where Size LIKE '%[^0-9]%' and [StockQuantity]>0
Group by [ProductVariantId]
order by Total Desc) as yüzde
FROM [Live_ADL].[dbo].[_INV_ProductCombinationAttributes]
Where Size LIKE '%[^0-9]%' and [StockQuantity]>0
group by [ProductVariantId]
order by yüzde desc
you don't really need a SP, you can do it in-line, using CTE for instance, something along these lines:
; with tabyuzde as
(
SELECT [ProductVariantId] ,
count([ProductVariantId]) as bedensayısı,
count([ProductVariantId]) * 100.0 / (SELECT Top 1 Count(*) as Total
FROM [Live_ADL].[dbo].[_INV_ProductCombinationAttributes]
Where Size LIKE '%[^0-9]%' and [StockQuantity]>0
Group by [ProductVariantId]
order by Total Desc) as yüzde
FROM [Live_ADL].[dbo].[_INV_ProductCombinationAttributes]
Where Size LIKE '%[^0-9]%' and [StockQuantity]>0
group by [ProductVariantId]
)
update x
set othertablevalue=yüzde
from
othertable x
join tabyuzde t on x.ProductVariantId=t.ProductVariantId

How to normalize group by count results?

How can the results of a "group by" count be normalized by the count's sum?
For example, given:
User Rating (1-5)
----------------------
1 3
1 4
1 2
3 5
4 3
3 2
2 3
The result will be:
User Count Percentage
---------------------------
1 3 .42 (=3/7)
2 1 .14 (=1/7)
3 2 .28 (...)
4 1 .14
So for each user the number of ratings they provided is given as the percentage of the total ratings provided by everyone.
SELECT DISTINCT ON (user) user, count(*) OVER (PARTITION BY user) AS cnt,
count(*) OVER (PARTITION BY user) / count(*) OVER () AS percentage;
The count(*) OVER (PARTITION BY user) is a so-called window function. Window functions let you perform some operation over a "window" created by some "partition" which is here made over the user id. In plain and simple English: the partitioned count(*) is calculated for each distinct user value, so in effect it counts the number of rows for each user value.
Without using a windowing function or variables, you will need to cross join a grouped subquery on a second "maxed" subquery then select again to return a subset you can work with.
SELECT
B.UserID,
B.UserCount,
A.CountAll
FROM
(
SELECT
CountAll=SUM(UserCount)
FROM
(
SELECT
UserCount=COUNT(*)
FROM
MyTable
GROUP BY
UserID
) AS A
)AS C
CROSS JOIN(
SELECT
UserID,
UserCount=COUNT(*)
FROM
MyTable
GROUP BY
UserID
)AS B

Firebird get the list with all available id

In a table I have records with id's 2,4,5,8. How can I receive a list with values 1,3,6,7. I have tried in this way
SELECT t1.id + 1
FROM table t1
WHERE NOT EXISTS (
SELECT *
FROM table t2
WHERE t2.id = t1.id + 1
)
but it's not working correctly. It doesn't bring all available positions.
Is it possible without another table?
You can get all the missing ID's from a recursive CTE, like this:
with recursive numbers as (
select 1 number
from rdb$database
union all
select number+1
from rdb$database
join numbers on numbers.number < 1024
)
select n.number
from numbers n
where not exists (select 1
from table t
where t.id = n.number)
the number < 1024 condition in my example limit the query to the max 1024 recursion depth. After that, the query will end with an error. If you need more than 1024 consecutive ID's you have either run the query multiple times adjusting the interval of numbers generated or think in a different query that produces consecutive numbers without reaching that level of recursion, which is not too difficult to write.