I have a table variable #WEEKS_MONTH like this:
I must update this table (column SUMMARY) with query:
SELECT SUM(AVAI_NUM)
FROM SCAVAI
WHERE AVAI_DST >= (SELECT WEEKSTART
FROM #WEEKS_MONTH
WHERE WEEKOFMONTH = 1)
AND AVAI_DST <= (SELECT WEEKEND
FROM #WEEKS_MONTH
WHERE WEEKOFMONTH = 1)
Problem that I have is that I don't know how to connect that table with this query. (WEEKOFMONTH must be from table, row by row. For example I've just put number 1.)
Just use a subquery in an UPDATE:
UPDATE wm
SET Summary = (SELECT SUM(s.AVAI_NUM)
FROM SCAVAI s
WHERE s.AVAI_DST BETWEEN wm.WEEK_START and wm.WEEK_END)
FROM #WEEKS_MONTH wm
Related
I'm trying to write a query that will select rows from a table but I'm struggling a little with there WHERE clause.
I have a list of C# objects that has an ID and a Date. I want to find rows in my database where the ID is equal to one of the ids in my list of objects, but at the same time, the Date that comes with the specific ID has to be between a ValidFrom and a ValidTo field in the Database.
I already a query that will work but it is not a very pretty solution:
SELECT *
FROM [dbo].[Employees] AS emp
WHERE emp.IsDeleted = 0
AND (emp.EmployeeId = 1
AND (emp.ValidFrom <= '2017-05-01')
AND (emp.ValidTo > '2017-05-01'))
OR (emp.EmployeeId = 2
AND (emp.ValidFrom <= '2018-05-01')
AND (emp.ValidTo > '2018-05-01'))
And then I'd proceed to add the 'OR' statement from there.
Is there a more optimal way for me to accomplish this?
You can populate the filtering criteria in a separate table:
CREATE TABLE #RecordsTobeFiltered
(
EmployeeId INT
,ValidFrom DATE
,ValidTo DATE
);
INSERT INTO #RecordsTobeFiltered (EmployeeId, ValidFrom, ValidTo)
VALUES (1, '2017-05-01', '2017-05-01')
,(2, '2018-05-01', '2018-05-01')
--- and many records as you need
SELECT *
FROM [dbo].[Employees] AS emp
INNER JOIN #RecordsTobeFiltered F
ON emp.EmployeeId = f.EmployeeId
and emp.ValidFrom <= f.ValidFrom
and emp.validTo > f.ValidTo
WHERE emp.IsDeleted = 0;
I want to update 15 records in that first 5 records date should be June 2019,next 5 records with July 2019,last 5 records with Aug 2019 based on employee id,Can any one tell me how to write this type of query in SQL Server Management Studio V 17.7,I've tried with below query but unable to do for next 5 rows..
Like below query
Update TOP(5) emp.employee(nolock) set statusDate=GETDATE()-31 where EMPLOYEEID='XCXXXXXX';
To update only a certain number of rows of a table you will need to include a FROM clause and join a sub-query which limits the number of rows. I would suggest using OFFSET AND FETCH instead of top so that you can skip X number of rows
You will also want to use the DATEADD function instead of directly subtracting a number from the DateTime function GETDATE(). I'm not certain but I think your query will subtract milliseconds. If you intend to go back a month I would suggest subtracting a month rather than 31 days. Alternatively it might be easier to specify an exact date like '2019-06-01'
For example:
TableA
- TableAID INT PK
- EmployeeID INT FK
- statusDate DATETIME
UPDATE TableA
SET statusDate = '2019-06-01'
FROM TableA
INNER JOIN
(
SELECT TableAID
FROM TableA
WHERE EmployeeID = ''
ORDER BY TableAID
OFFSET 0 ROWS
FETCH NEXT 5 ROWS ONLY
) T1 ON TableA.TableAID = T1.TableAID
Right now it looks like your original query is updating the table employee rather than a purchases table. You will want to replace my TableA with whichever table it is you're updating and replace TableAID with the PK field of it.
You can use a ROW_NUMBER to get a ranking by employee, then just update the first 15 rows.
;WITH EmployeeRowsWithRowNumbers AS
(
SELECT
T.*,
RowNumberByEmployee = ROW_NUMBER() OVER (
PARTITION BY
T.EmployeeID -- Generate a ranking by each different EmployeeID
ORDER BY
(SELECT NULL)) -- ... in no particular order (you should supply one if you have an ordering column)
FROM
emp.employee AS T
)
UPDATE E SET
statusDate = CASE
WHEN E.RowNumberByEmployee <= 5 THEN '2019-06-01'
WHEN E.RowNumberByEmployee BETWEEN 6 AND 10 THEN '2019-07-01'
ELSE '2019-08-01' END
FROM
EmployeeRowsWithRowNumbers AS E
WHERE
E.RowNumberByEmployee <= 15
I have a temp table that contains the following data:
The WV1 column needs to be updated to the department value for all rows that share the same date for example;
WV1 = 19176 for all 2017-11-08 00:00:00.000 rows
WV1 = 18067 for all 2017-11-06 00:00:00.000 rows
The WV1 column may remain as NULL if there is no 215 code but it doesn't matter for my purposes, I can't create other temp tables meaning I'm restricted to CTE or subqueries, thanks in advance for any help!
You can use the following using CTE:
;WITH CTE AS
(SELECT IDNO, [DATE], DEPARTMENT
FROM #TAB
WHERE CODE = 215
)
UPDATE T
SET WV1 = C.DEPARTMENT
FROM #TAB T
JOIN CTE C ON C.IDNO = T.IDNO AND C.[DATE] = T.[DATE]
Thanks.
Here's my data;
table A.pickup_date is a date column
table A.biz_days is the business days I want to add up to A.pickup_date
table B.date
table B.is_weekend (Y or N)
table B. is_holiday (Y or N)
Basically from table B, I know for each date, if any date is a business day or not. Now I want to have a third column in table A for the exact date after I add A.business_days to A.pickup_date.
Can anyone provide me with either a case when statement or procedure statement for this? Unfortunately we are not allowed to write our own functions in Teradata.
This is pretty darned ugly, but I think it should get you started.
First I created a volatile table to represent your table a:
CREATE VOLATILE TABLE vt_pickup AS
(SELECT CURRENT_DATE AS pickup_date,
8 AS Biz_Days) WITH DATA PRIMARY INDEX(pickup_date)
ON COMMIT PRESERVE ROWS;
INSERT INTO vt_pickup VALUES ('2015-02-24',5);
Then I joined that with sys_calendar.calendar to get the days of the week:
CREATE VOLATILE TABLE VT_Days AS
(
SELECT
p.pickup_date,
day_of_week
FROM
vt_pickup p
INNER JOIN sys_calendar.CALENDAR c
ON c.calendar_date >= p.pickup_date
AND c.calendar_date < (p.pickup_date + Biz_Days)
) WITH DATA
PRIMARY INDEX(pickup_date)
ON COMMIT PRESERVE ROWS
Then I can use all that to generate the actual delivery date:
SELECT
p.pickup_date,
p.biz_days,
biz_days + COUNT(sundays.day_of_week) + COUNT (saturdays.day_of_week) AS TotalDays,
COUNT (sundays.day_of_week) AS Suns,
COUNT (saturdays.day_of_week) AS Sats,
p.pickup_date + totaldays AS Delivery_Date,
FROM
vt_pickup p
LEFT JOIN vt_days AS Sundays ON
p.pickup_date = sundays.pickup_date
AND sundays.day_of_week = 1
LEFT JOIN vt_days AS saturdays ON
p.pickup_date = saturdays.pickup_date
AND saturdays.day_of_week = 7
GROUP BY 1,2
You should be able to use the logic with another alias for your holidays.
The easiest way to do this is calculating a sequential number of business days (add it as a new column to your calendar table if it's a recurring operation, otherwise using WITH):
SUM(CASE WHEN is_weekend = 'Y' OR is_holiday = 'Y' THEN 0 ELSE 1 END)
OVER (ORDER BY calendar_date
ROWS UNBOUNDED PRECEDING) AS biz_day#
Then you need two joins:
SELECT ..., c2.calendar_date
FROM tableA AS a
JOIN tableB AS c1
ON a.pickup_date = c1.calendar_date
JOIN tableB AS c2
ON c2.biz_day# = c1.biz_day# + a.biz_days
AND is_weekend = 'N'
AND is_holiday = 'N'
I want to update multiple tables and values after inserting values in one table so I created a trigger. It works fine for inserts of one row, but as soon I insert more rows, SQL Server gives me following error:
subquery returned more than 1 value. this is not permitted when the subquery follows = or when the subquery is used as an expression?
Here is my trigger:
CREATE TRIGGER [dbo].[tbl_Sales_ForInsert]
ON [dbo].[SALES]
FOR INSERT
AS
BEGIN
DECLARE #ITEMMODEL varchar(100)
SELECT #ITEMMODEL = ITEM_MODEL FROM inserted
UPDATE SALES
SET PROFIT = TOTAL_PRICE - (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL) * (SELECT RATE FROM ITEM_DETAILS WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL
UPDATE ITEM_DETAILS
SET QUANTITY = QUANTITY - (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL
--UPDATE ITEM_DETAILS SET AMOUNT = AMOUNT - (SELECT RATE FROM ITEM_DETAILS WHERE ITEM_MODEL=#ITEMMODEL) * (SELECT QUANTITY FROM SALES WHERE ITEM_MODEL=#ITEMMODEL) where ITEM_MODEL=#ITEMMODEL
END
As I insert data in SALES table for 1st time the update got successful but for 2nd time it gives me above error remember ITEM_MODEL is foreign key constraint in SALES table.
I have been suffering with this error can anyone help me please?
Your fundamental flaw is that you seem to expect the trigger to be fired once per row - this is NOT the case in SQL Server. Instead, the trigger fires once per statement, and the pseudo table Inserted might contain multiple rows.
Given that that table might contain multiple rows - which one do you expect will be selected here??
SELECT #ITEMMODEL = ITEM_MODEL FROM inserted
It's undefined - you might get the values from arbitrary rows in Inserted.
You need to rewrite your entire trigger with the knowledge the Inserted WILL contain multiple rows! You need to work with set-based operations - don't expect just a single row in Inserted!
So in your case, your trigger code should look something like this:
CREATE TRIGGER [dbo].[tbl_Sales_ForInsert]
ON [dbo].[SALES]
FOR INSERT
AS
BEGIN
-- update the dbo.Sales table, set "PROFIT" to the difference of
-- TOTAL_PRICE and (QUANTITY * RATE) from the "Inserted" pseudo table
UPDATE s
SET s.PROFIT = i.TOTAL_PRICE - (i.QUANTITY * i.RATE)
FROM dbo.Sales s
INNER JOIN Inserted i ON i.ITEM_MODEL = s.ITEM_MODEL
-- update the dbo.ITEM_DETAILS table
UPDATE id
SET id.QUANTITY = id.QUANTITY - i.Quantity
FROM dbo.ITEM_DETAILS id
INNER JOIN Inserted i ON id.ITEM_MODEL = i.ITEM_MODEL
END
Marc_s is right about expecting the inserted pseudo table containing more than one row. There are instances that a query might work if a subquery was just limited to one row with a TOP(1).
UPDATE SALES
SET PROFIT = TOTAL_PRICE - (SELECT TOP(1) QUANTITY FROM SALES WHERE ITEM_MODEL = #ITEMMODEL)
* (SELECT TOP(1) RATE FROM ITEM_DETAILS WHERE ITEM_MODEL = #ITEMMODEL)
WHERE ITEM_MODEL = #ITEMMODEL