Updating table based on the interval from another. SQL Server - sql

I need to count how many men was working each hour. I have two tables:
Hour Men
------------
6 0
7 0
8 0
9 0
10 0
11 0
12 0
where "Men" column is the count of men. Another table is:
ClockedInHour ClockedOutHour
6 10
7 10
8 12
6 11
9 12
So for every entry in the second table, I need to increment "Men" column in the first table for every hour between "ClockedInHour" and "ClockedOutHour" including those in the table, and, if possible, to do it without cursor.
Additional condition: it will be a part of the table-valued function.
Thanks in advance for your help.

Solved!
DECLARE #Hour6 INT
SET #Hour6 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 6 and ClockedInHour <= 6)
DECLARE #Hour7 INT
SET #Hour7 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 7 and ClockedInHour <= 7)
DECLARE #Hour8 INT
SET #Hour8 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 8 and ClockedInHour <= 8)
DECLARE #Hour9 INT
SET #Hour9 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 9 and ClockedInHour <= 9)
DECLARE #Hour10 INT
SET #Hour10 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 10 and ClockedInHour <= 10)
DECLARE #Hour11 INT
SET #Hour11 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 11 and ClockedInHour <= 11)
DECLARE #Hour12 INT
SET #Hour12 = (SELECT COUNT(*) FROM #tc where ClockedOutHour >= 12 and ClockedInHour <= 12)
UPDATE #table1 SET Man = #Hour6 WHERE Hour = 6
UPDATE #table1 SET Man = #Hour7 WHERE Hour = 7
UPDATE #table1 SET Man = #Hour8 WHERE Hour = 8
UPDATE #table1 SET Man = #Hour9 WHERE Hour = 9
UPDATE #table1 SET Man = #Hour10 WHERE Hour = 10
UPDATE #table1 SET Man = #Hour11 WHERE Hour = 11
UPDATE #table1 SET Man = #Hour12 WHERE Hour = 12

You can do this using a Insert Trigger as:
Go --terminate all preceding batch of statements
CREATE TRIGGER tg_MenCount ON dbo.table2 For INSERT
AS
SET XACT_ABORT, NOCOUNT ON
--Ignore zero row updates, inserts
IF NOT EXISTS (SELECT * FROM INSERTED) RETURN;
BEGIN TRY
UPDATE T1
set T1.men = T1.men +1
FROM
table1 T1
INNER JOIN INSERTED I
ON T1.hour between I.ClockedInHour and I.ClockedOutHour
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION
--RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
GO

Related

Fill up column with random values from different table

I have 2 tables. Table Table_View has 5 columns and 200 rows
and Table_Random has 3 columns with 10 rows
I need to poulate column Table_View.A_random with values from
Table_Random.FixValues. If the query reaches the end of row in Table_Random i.e row 10, it should start again with
values from the top row i.e row 1. until it fills up the 200 rows.
Given that all tables has primary keys.
Any Ideas?
Thanks in advance
This will work for any count of rows in destination and source tables.
The idea is to calculate count of rows in random table and then assign number rn % #c to each row in destination table. And then update based on join:
DECLARE #count INT = 21
DECLARE #i INT = 1
DECLARE #c INT = 0
DECLARE #t TABLE ( ID INT, Random INT )
DECLARE #r TABLE ( ID INT, Random INT )
INSERT INTO #r
VALUES ( 1, 10 ),
( 3, 20 ),
( 4, 30 ),
( 6, 40 ),
( 8, 50 ),
( 11, 60 ),
( 14, 70 ),
( 17, 80 ),
( 19, 90 ),
( 21, 100 )
WHILE #i <= #count
BEGIN
INSERT INTO #t
VALUES ( #i, NULL )
SET #i = #i + 1
END;
SELECT #c = COUNT(*)
FROM #r;
WITH ctet1
AS ( SELECT * , ROW_NUMBER() OVER ( ORDER BY ID ) AS rn
FROM #t
),
ctet2
AS ( SELECT * ,
CASE WHEN rn % #c = 0 THEN #c
ELSE rn % #c
END AS rnn
FROM ctet1
),
cter
AS ( SELECT * , ROW_NUMBER() OVER ( ORDER BY ID ) AS rn
FROM #r
)
UPDATE ct
SET Random = cr.Random
FROM ctet2 ct
JOIN cter cr ON cr.rn = ct.rnn
SELECT * FROM #t
Output:
ID Random
1 10
2 20
3 30
4 40
5 50
6 60
7 70
8 80
9 90
10 100
11 10
12 20
13 30
14 40
15 50
16 60
17 70
18 80
19 90
20 100
21 10
If you didn't want cycle update then no need for views, functions and needless stuff. Just update:
UPDATE #t SET Random = (SELECT TOP 1 Random FROM #r ORDER BY NEWID())
yes you can make this out.
First of all you need to create and view which'll return a single value from Random Table(Table_Random) for every call.
Create View vMyRand as
Select top 1 val from myRand order by NewID();
then create a function to return value from created view.
CREATE FUNCTION GetMyRand ()
RETURNS varchar(5)
--WITH EXECUTE AS CALLER
AS
BEGIN
Declare #RetValue varchar(5)
--#configVar =
Select #RetValue = val from vmyRand
RETURN(#retValue)
END;
Fiddle Demo Here
Full Code:
create table tab_1
(
id bigint identity(1,1),
name varchar(50),
email varchar(50)
)
insert into tab_1(name,email) values
('a','a#mail.com'), ('b','c#mail.com'),
('a1','a1#mail.com'), ('a2','a2#mail.com'),
('a3','a3#mail.com'), ('a4','a4#mail.com'),
('b1','b1#mail.com'),('b2','b2#mail.com')
create table myRand(val varchar(50))
insert into myRand values('Q1654'),('F2597'),
('Y9405'),('B6735'),('D8732'),('C4893'),('I9732'),
('L1060'),('H6720');
Create View vMyRand as
Select top 1 val from myRand order by NewID();
CREATE FUNCTION GetMyRand ()
RETURNS varchar(5)
--WITH EXECUTE AS CALLER
AS
BEGIN
Declare #RetValue varchar(5)
--#configVar =
Select #RetValue = val from vmyRand
RETURN(#retValue)
END;
Update Code:
update tab_1 set name=(select dbo.getMyRand())
Hope This'll Help You.
Thanks. :)

Right way to subtract in a stored procedure

I have the following query in my stored procedure
DECLARE #I INT
DECLARE #TenPercent int
DECLARE #RowsCount int
SET #TenPercent =10
SET #I = 1
SELECT
#I, dbo.tblVegetationType.VegTypeCode, dbo.tblVegetationType.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegTypeVegFormationLink ON dbo.tblVegetationType.VegTypeID = dbo.tblVegTypeVegFormationLink.VegTypeID
INNER JOIN
tblCMAVegTypeLink ON dbo.tblVegetationType.VegTypeID = dbo.tblCMAVegTypeLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
AND dbo.tblVegTypeVegFormationLink.VegetationFormationID = #VegetationFormationID
AND dbo.tblCMAVegTypeLink.CMAID = #CMAID
I have following condition
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
What I am trying to do here: if PercentCleared is 60% then I want to query to pick the list from 50 %.
So I just add the SET #TenPercent = 10 and subtract from the condition.
Is that a right way to do?
Another way of writing the query can be:
SELECT #I,
VT.VegTypeCode,
VT.VegTypeName
FROM dbo.tblVegetationType VT
INNER JOIN dbo.tblVegTypeVegFormationLink VTVF
ON VT.VegTypeID = VTVF.VegTypeID
INNER JOIN tblCMAVegTypeLink CVT
ON VT.VegTypeID = CVT.VegTypeID
WHERE 1= case when #PercentCleared >= 60 and VT.PercentageCleared <= 50 then 1
-- you can add condition when #PercentCleared < 60 then what values of
-- VT.PercentageCleared are to be considered
when #PercentCleared < 60 and VT.PercentageCleared <= 50 then 1
end
AND VTVF.VegetationFormationID = #VegetationFormationID
AND CVT.CMAID = #CMAID

Sequential numbers randomly selected and added to table

The SO Question has lead me to the following question.
If a table has 16 rows I'd like to add a field to the table with the numbers 1,2,3,4,5,...,16 arranged randomly i.e in the 'RndVal' field for row 1 this could be 2, then for row 2 it could be 5 i.e each of the 16 integers needs to appear once without repetition.
Why doesn't the following work? Ideally I'd like to see this working then to see alternative solutions.
This creates the table ok:
IF OBJECT_ID('tempdb..#A') IS NOT NULL BEGIN DROP TABLE #A END
IF OBJECT_ID('tempdb..#B') IS NOT NULL BEGIN DROP TABLE #B END
IF OBJECT_ID('tempdb..#C') IS NOT NULL BEGIN DROP TABLE #C END
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL BEGIN DROP TABLE #myTable END
CREATE TABLE #B (B_ID INT)
CREATE TABLE #C (C_ID INT)
INSERT INTO #B(B_ID) VALUES
(10),
(20),
(30),
(40)
INSERT INTO #C(C_ID)VALUES
(1),
(2),
(3),
(4)
CREATE TABLE #A
(
B_ID INT
, C_ID INT
, RndVal INT
)
INSERT INTO #A(B_ID, C_ID, RndVal)
SELECT
#B.B_ID
, #C.C_ID
, 0
FROM #B CROSS JOIN #C;
Then I'm attempting to add the random column using the following. The logic is to add random numbers between 1 and 16 > then to effectively overwrite any that are duplicated with other numbers > in a loop ...
SELECT
ROW_NUMBER() OVER(ORDER BY B_ID) AS Row
, B_ID
, C_ID
, RndVal
INTO #myTable
FROM #A
DECLARE #rowsRequired INT = (SELECT COUNT(*) CNT FROM #myTable)
DECLARE #i INT = (SELECT #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable)--0
DECLARE #end INT = 1
WHILE #end > 0
BEGIN
SELECT #i = #rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable
WHILE #i>0
BEGIN
UPDATE x
SET x.RndVal = FLOOR(RAND()*#rowsRequired)
FROM #myTable x
WHERE x.RndVal = 0
SET #i = #i-1
END
--this is to remove possible duplicates
UPDATE c
SET c.RndVal = 0
FROM
#myTable c
INNER JOIN
(
SELECT RndVal
FROM #myTable
GROUP BY RndVal
HAVING COUNT(RndVal)>1
) t
ON
c.RndVal = t.RndVal
SET #end = ##ROWCOUNT
END
TRUNCATE TABLE #A
INSERT INTO #A
SELECT
B_ID
, C_ID
, RndVal
FROM #myTable
If the original table has 6 rows then the result should end up something like this
B_ID|C_ID|RndVal
----------------
| | 5
| | 4
| | 1
| | 6
| | 3
| | 2
I don't understand your code, frankly
This will update each row with a random number, non-repeated number between 1 and the number of rows in the table
UPDATE T
SET SomeCol = T2.X
FROM
MyTable T
JOIN
(
SELECT
KeyCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T2 ON T.KeyCol = T2.KeyCol
This is more concise but can't test to see if it works as expected
UPDATE T
SET SomeCol = X
FROM
(
SELECT
SomeCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
FROM
MyTable
) T
When you add TOP (1) (because you need to update first RndVal=0 record) and +1 (because otherwise your zero mark means nothing) to your update, things will start to move. But extremely slowly (around 40 seconds on my rather outdated laptop). This is because, as #myTable gets filled with generated random numbers, it becomes less and less probable to get missing numbers - you usually get duplicate, and have to start again.
UPDATE top (1) x
SET x.RndVal = FLOOR(RAND()*#rowsRequired) + 1
FROM #myTable x
WHERE x.RndVal = 0
Of course, #gbn has perfectly valid solution.
This is basically the same as the previous answer, but specific to your code:
;WITH CTE As
(
SELECT B_ID, C_ID, RndVal,
ROW_NUMBER() OVER(ORDER BY NewID()) As NewOrder
FROM #A
)
UPDATE CTE
SET RndVal = NewOrder
SELECT * FROM #A ORDER BY RndVal

NULL value returned when using SUM function on two columns while populating table in SQL Server 2008

INSERT INTO table is producing a NULL value for the returned recordset. I'm trying to add the SUM(m.earnings + m.fpearn) from pfinancial table and userid & minpay from the userbase table.
What am I doing wrong? Also is there a better way to reiterate through the temp table of id's ?
From the tables below I should populate the publsher_monthly table with one unique id per userid, the minpay amount from the userbase and the sum of the m.earnings + m.fpearn columns from the pfinancial table
publisher_monthly table
pmuseris pmminpay pmearnings
5 20 75
6 30 27
userbase table
userid minpay
5 20
6 30
pfinancial table
userid earnings fpearn
5 10 30
5 20 15
6 15 12
My query:
DECLARE #realuserid bigint
CREATE TABLE #tmppmuserids(
idx bigint Primary Key IDENTITY(1,1),
tmppmuserid bigint NULL
)
INSERT INTO #tmppmuserids
SELECT DISTINCT userid FROM pfinancial
DECLARE #i bigint
DECLARE #numrows bigint
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #tmppmuserids)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #tmppmuserids))
BEGIN
SET #realuserid = (SELECT tmppmuserid FROM #tmppmuserids WHERE idx = #i)
--PROBLEM HERE
INSERT INTO publisher_monthly (pmearnings, pmuserid, pmminpay)
SELECT
SUM(m.earnings + m.fpearn), MAX(#realuserid), MAX(u.minpay)
FROM pfinancial m
INNER JOIN userbase u on u.userid = m.userid
WHERE
m.userid = #realuserid AND
(m.created >= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()),0)) AND
(m.created < DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()) + 1, 0))
--END PROBLEM
SET #i = #i + 1
END
SELECT * FROM #tmppmuserids
SELECT * FROM publisher_monthly
DROP TABLE #tmppmuserids
Place an IsNull around them:
SELECT SUM(IsNull(m.earnings, 0) + IsNull(m.fpearn, 0))
or even around the whole thing:
SELECT IsNull(SUM(m.earnings + m.fpearn), 0)

get specific rows of table given a rule SQL Server 2008

I have a table like:
ID NAME VAL
----------------------
1 a1*a1 90052
2 a1*a2 236
3 a1*a3 56
4 a1*a4 6072
5 a1*a5 1004
6 a2*a2 4576
7 a2*a3 724
8 a2*a4 230
9 a2*a5 679
10 a3*a3 5
11 a3*a4 644
12 a3*a5 23423
13 a4*a4 42354
14 a4*a5 10199
15 a5*a5 10279
Given a number given S = 5, I want to query
the rows wth id: 1,6,10,13,15
they are a1*a1,a2*a2,a3*a3,a4*a4 and a5*a5
I would like something like:
INSERT #NEW_TABLE (ID,NAME,Value) (
SELECT ordinal, NAME, VAL FROM myTable where id = 1,6,10,13,15)
to get
ID NAME VAL
----------------------
1 a1*a1 90052
2 a2*a2 4576
3 a3*a3 5
4 a4*a4 42354
5 a5*a5 10279
Is there a way to do this for any given S, Maybe wth dynamic sql?
I was getting the formula and I got this:
S=5
ID formula
1 1
6 1+S
10 1+S+ (S-1)
13 1+S+ (S-1) + (S-2)
15 1+S+ (S-1) + (S-2) + (S-3)
Is there a way to do this inside a case or a while loop?
This worked in testing.
You can just inner join on #Tab to limit your results. You probably also want to add some traps for values below 3, which I haven't done.
The basic process is
Declare your #s value
Insert the first two rows since they will always be the same
In a loop, insert one row at a time with an incrementing difference
Loop exits once it has run #s-2 times
Try:
DECLARE #Tab Table (id INT)
DECLARE #S int = 5,
#ct int
DECLARE #cur int = (1 + #S)
INSERT INTO #Tab SELECT 1
INSERT INTO #Tab SELECT (1 + #S)
SET #ct = 1
WHILE #ct <= #S - 2
BEGIN
SET #cur = #cur + (#S - #ct)
INSERT INTO #Tab SELECT #cur
SET #ct = #ct + 1
END
SELECT * FROM #Tab
ORDER BY id
To use this in your query, you can do either:
SELECT ordinal, NAME, VAL
FROM myTable
WHERE id IN (SELECT id FROM #Tab)
-- OR
SELECT ordinal, NAME, VAL
FROM myTable t
INNER JOIN #tab t2
ON t2.id = t.id