SQL Server - Variation auto increment based on primary key - sql

my scenario is this:
Say within an engineering environment, works for a job are quoted at £5,000. However after this a variation is made an additional cost is required for £500.
now within SQL Server I have a table, lets call it Costing. This is associated to the Customer table (1 to many) 1 Customer could have many costs...
Now my question is this... is it possible to auto increment a variation number within the CostingTable, baring in mind that the CostingID is already auto incrementing or is there a different approach I can take?
Example data:
ive already done all the costing calculations etc so this is no issue, its just if it is possible to automatically add one to the VariationNumber based upon the CustomerID... thanks guys

If you want just to display it then use this:
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CustomerId ORDER BY CostingId) AS Variation
FROM Costing
But if you want to store it:
;WITH MyCTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CustomerId ORDER BY CostingId) AS NewVariation
FROM Costing
)
UPDATE MyCTE
SET Variation = NewVariation

Related

Query for records only where the Project Status has changed

I'm trying to write a query where I return only the records where the status of a project changes. Projects start off "In Progress," can "Pause," go back "In Progress," and continue until they are "Completed." The table is designed for the full history of modifications toward the project and details of the project cause a new record to be created. So, table structure will look like below, and the highlighted records are what I want to query for:
I've tried to use a combination of ROW_NUMBER() and RANK() with certain elements but I can't get seem to get it right. How do I query for the records where the status changes? This post and this post are similar but don't help.
Thanks to #klin for the LAG() recommendation.
WITH l as (
SELECT LAG(status, 1) OVER (PARTITION BY mod_id ORDER BY mod_date) lag, *
FROM projects_table
ORDER BY mod_id, mod_date
)
SELECT *
FROM l
WHERE lag IS DISTINCT FROM status
ORDER BY mod_date

How to get last value from a table category wise?

I have a problem with retrieving the last value of every category from my table which should not be sorted. For example i want the daily inventory value of nov-1 last appearance in the table without sorting the column daily inventory i.e "471". Is there a way to achieve this?
similarly i need to get the value of the next week's last daily inventory value and i should be able to do this for multiple items in the table too.
p.s: nov-1 represents nov-1 st week
Question from comments of initial post: will I be able to achieve what I need if I introduce a column id? If so, how can I do it?
Here's a way to do it (no guarantee that it's the most efficient way to do it)...
;WITH SetID AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY Week ORDER BY Week) AS rowid, * FROM <TableName>
),
MaxRow AS
(
SELECT LastRecord = MAX(rowid), Week
FROM SetID
GROUP BY Week
)
SELECT a.*
FROM SetID a
INNER JOIN MaxRow b
ON a.rowid = b.LastRecord
AND b.Week = a.Week
ORDER BY a.Week
I feel like there's more to the table though, and this is also untested on large amounts of data. I'd be afraid that a different RowID could be potentially assigned upon each run. (I haven't used ROW_NUMBER() enough to know if this would throw unexpected data.)
I suppose this example is to enforce the idea that, if you had a dedicated rowID on the table, it's possible. Also, I believe #Larnu's comment to you on your original post - introducing an ID column that retains current order, but reinserting all your data - is a concern too.
Here's a SQLFiddle example here.

SQL schema Site Leader Board

So I am trying to set up a site which has challenges and then want to convert that to leader boards for each challenge, and then an all time leaderboard.
So I have a challenges table that looks like this:
Challenge ID Challenge Name Challenge Date Sport Prize Pool
Then I need a way so each challenge has its own leader board of say 50 people.
linked by the challenge ID where that will = Leaderboard ID
I have a leader board of 50 people for that challenge that will look something like this:
Challenge ID User Place Prize Won
My question is 2 things:
How can I make a table auto create when a new challenge is added to the challenges table?
How can I get an A site wide leader board for every challenge so it will show the following:
Rank USER Prize Money Won(total every challenge placed)
and then base rank order by how much money won..
I know this is a lot of questions all wrapped in one, schema design and logic.
Any insights greatly appreciated
A better approach than one table per challenge is one table for all of them. That way you can compute grand totals and individual challenge rankings all with the same table. You'd also want to not record the place directly but compute it on the fly with the appropriate window function depending on how you want to handle ties (rank(), dense_rank(), and row_number() will have different results in those cases); that way you don't have to keep adjusting it as you add new records.
A table something like (You didn't specify a SQL database, so I'm going to assume Sqlite. Adjust as needed.):
CREATE TABLE challenge_scores(user_id INTEGER REFERENCES users(id),
challenge_id INTEGER REFERENCES challenges(id),
prize_amount NUMERIC,
PRIMARY KEY(user_id, challenge_id));
will let you do things like
SELECT *
FROM (SELECT user_id,
sum(prize_amount) AS total,
rank() OVER (ORDER BY sum(prize_amount) DESC) AS place
FROM challenge_scores
GROUP BY user_id)
WHERE place <= 50
ORDER BY place;
for the global leaderboard, or the similar:
SELECT *
FROM (SELECT user_id,
prize_amount,
rank() OVER (ORDER BY prize_amount DESC) AS place
FROM challenge_scores
WHERE challenge_id = :some_challenge_id
GROUP BY user_id)
WHERE place <= 50
ORDER BY place;
for a specific challenge's.

SQL select the first match in an ordered list

Using Microsoft SQL Server Management Studio version 14.0.17213.0
I have a list of events that go in order. I want to select the highest precedent acct_no, complete_date and event.
My problem is if I use
select
account_number, event, max(complete_date) as mx_comp
from
mytable
where
event in ('event1','event2'....)
then I get all my acct_numbers, all the events in the list and the max complete date for that event. But I want acct_no listed with the maximum completed date for any item in the list and the associated event.
Furthermore, its wholly possible that two events occurred on the same date, so I cannot do
select *
from mytable mt
join
(select acct_number, max(complete_date)
from mytable) t on mt.acct_number = t.account_number
and mt.complete_date = t.complete_date
because if two events occurred on the same day then I still get duplicate results.
I have tried to do a similar thing with
row_number() over (order by account_number) as RowNum
but it did not work, because I still get matches to all the events, not just my highest precedence event
it really boils down to needing to return the acct_number, event and complete date associated to the highest importance match from items in an ordered list.
I am sure it is easy - I just cannot seem to figure it out and despite all my google and stack searching I simply cannot figure it out
I have recently been thinking that it might be possible with something like coalesce(mylist) because I would be able to put my list in order but I cannot figure out how to use coalesce in a meaningful way for this problem.
The real solution would be to create a table with precedence numbers or have a most recent indicator but I dont have unlimited access to create any tables I want.
Any help or ideas on how to match to an ordered list would be appreciated
You seem to want:
select t.*
from (select t.*,
row_number() over (partition by account_number order by complete_date desc) as seqnum
from mytable t
where event in ('event1', 'event2', ....)
) t
where seqnum = 1;

SQL Server - how to select x number of task per x number of workers

I need some help writing a query in SQL Server 2012 to select a specific number of tasks per a selected number of workers. If I was doing something like this is a traditional programming language I would use something like a foreach. However I can't find a nice way to implement a foreach function into sql. I'm sure there is a simpler way to do this.
For example, lets say I have 3 tables:
MonthlyReview
DateReviewed,
WorkerID
Workers
WorkerID,
WorkerName
Tasks
TaskID,
WorkerID
First I select the workers I want to be selecting from (they are filtered on some other data such as name or org (not pictured)) so I thought it would make things easier to put it in a temp table
CREATE TABLE #WorkersToAudit (
WorkerID varchar(45),
DateReviewed datetime)
INSERT INTO #WorkersToAudit(WorkerID, DateReviewed)
SELECT TOP (4) Workers.WorkerID, MIN(MonthlyReview.DateReviewed) AS DateReviewed FROM Workers
LEFT JOIN MonthlyReview ON Workers.WorkerID = MonthlyReview.WorkerID
WHERE Workers.WorkerName LIKE '%Browne%'
GROUP BY Worker.WorkerID
DROP TABLE #WorkersToAudit
I was thinking I could then grab the (4) WokerID's in the results and find (4) TaskID's for each, but I haven't found a nice way to do this despite a lot of searching. The number of WorkerID's searched for and the number of TraderID's returned for each one can be anywhere from 1-10.
Any help would be greatly appreciated.
The easiest way to do this in one query is to use WINDOWING functions. In this case ROW_NUMBER() will work:
select WorkerID, TaskID
FROM (
SELECT Workers.WorkerID, Tasks.TaskID,
row_number() over (partition by Workers.WorkerID order by Tasks.TaskID) AS rn
FROM Workers
LEFT JOIN Tasks ON Workers.WorkerID = Tasks.WorkerID
WHERE Workers.WorkerName LIKE '%Browne%'
) where rn <= 4
Notice the key parts of the over clause of the row_number() function - the partition by essentially "groups" the counting of rows by WorkerID, and the order by specifies, well, the ordering of rows that are counted.
You can change how the row_number does its grouping and ordering, and you can include whatever columns you want in the select clause, but the key part is indeed the use of the row_number() function itself.
Good luck!