SQL Server INSERT INTO with WHERE clause - sql

I'm trying to insert some mock payment info into a dev database with this query:
INSERT
INTO
Payments(Amount)
VALUES(12.33)
WHERE
Payments.CustomerID = '145300';
How can adjust this to execute? I also tried something like this:
IF NOT EXISTS(
SELECT
1
FROM
Payments
WHERE
Payments.CustomerID = '145300'
) INSERT
INTO
Payments(Amount)
VALUES(12.33);

I think you are trying to do an update statement (set amount = 12.33 for customer with ID = 145300)
UPDATE Payments
SET Amount = 12.33
WHERE CustomerID = '145300'
Else if you are trying to insert a new row then you have to use
IF NOT EXISTS(SELECT 1 FROM Payments WHERE CustomerID = '145300')
INSERT INTO Payments(CustomerID,Amount)
VALUES('145300',12.33)
Or if you want to combine both command (if customer exists do update else insert new row)
IF NOT EXISTS(SELECT 1 FROM Payments WHERE CustomerID = '145300')
INSERT INTO Payments(CustomerID,Amount)
VALUES('145300',12.33)
ELSE
UPDATE Payments
SET Amount = 12.33
WHERE CustomerID = '145300'

If you want to insert new rows with the given CustomerID
INSERT
INTO
Payments(Amount,CustomerID )
VALUES(12.33,'145300');
else if you already have payment for the customer you can do:
UPDATE
Payments
SET Amount = 12.33
WHERE
CustomerID = '145300';

It sounds like having the customerID already set. In that case you should use an update statement to update a row. Insert statements will add a completely new row which can not contain a value.

Do you want to perform update;
update Payments set Amount = 12.33 where Payments.CustomerID = '145300'

i do inserts into a table if the record doesn't exist this way. may not be entirely what is after but it may be helpful
insert into x (a,b)
select 1,2
where 0=(select count(*) from x where a = 1 and b = 2)

Ok, looks like I actually need to just do an insert into the Payments table that has the correct CustomerID, as there are currently no Payments with that CustomerID, so I cannot update it.
I ran INSERT INTO Payments (CustomerID, Amount, PaymentTypeID) Values ('145300', 24.99, 8); and then SELECT * FROM Payments WHERE Payments.CustomerID = '145300'; to confirm and we're in business. Thanks everyone!

Better solution and without risk of deadlocks:
UPDATE Payments
SET Amount = 12.33
WHERE CustomerID = '145300'
INSERT INTO Payments(CustomerID,Amount)
SELECT '145300',12.33
WHERE ##ROWCOUNT=0

Try to update as below if you want to modify existing row,
UPDATE Payments SET Amount = 12.33 WHERE CustomerID = '145300';

Related

Working with query to archive customer data

I have a Customers table, a Transactions table, and a Payments table. The Transactions table represents charges to a customer, and the Payments table represents credits to a customer. (Both tables have foreign keys to the Customers table.)
A customer's balance is calculated using Customers.StartingBalance, plus the sum of all that customer's charges in the Transactions table, minus the sum of all that customer's payments in the Payments table.
Now I want to implement an archive feature that deletes all transactions and payments prior to a given date, and then updates Customers.StartingBalance so that the final balance (calculated as described in the previous paragraph) remains the same.
Here's what I have so far:
ALTER PROCEDURE [dbo].[ArchiveData] #ArchiveDateTime DATETIME
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #CustomerBalance TABLE
(
CustomerId INT,
Amount BIGINT
);
BEGIN TRANSACTION;
-- Archive transactions
DELETE Transactions WITH (TABLOCK)
OUTPUT deleted.CustomerId, deleted.TotalAmount INTO #CustomerBalance
WHERE [TimeStamp] < #ArchiveDateTime;
IF EXISTS (SELECT 1 FROM #CustomerBalance)
BEGIN
UPDATE Customers SET StartingBalance = StartingBalance +
(SELECT SUM(Amount) FROM #CustomerBalance cb WHERE Id = cb.CustomerId)
END;
DELETE FROM #CustomerBalance
-- Archive payments
DELETE Payments WITH (TABLOCK)
OUTPUT deleted.CustomerId, deleted.Amount INTO #CustomerBalance
WHERE [Date] < #ArchiveDateTime;
IF EXISTS (SELECT 1 FROM #CustomerBalance)
BEGIN
UPDATE Customers SET StartingBalance = StartingBalance -
(SELECT SUM(Amount) FROM #CustomerBalance cb WHERE Id = cb.CustomerId)
END;
-- Probably not needed
DELETE FROM #CustomerBalance
COMMIT TRANSACTION;
END
Since SQL is not my core competency, I'd like to get feedback on this. Does it seem "correct"? Does it seem optimal? Also, I'm not sure about clauses like the following.
UPDATE Customers SET StartingBalance = StartingBalance -
(SELECT SUM(Amount) FROM #CustomerBalance cb WHERE Id = cb.CustomerId)
What does this do where #CustomerBalance contains no rows for the customer?
What does this do where #CustomerBalance contains multiple rows for the customer?
Thanks for any suggestions.
About your last question
-- i would add the name of the outer query table in the inner one
UPDATE Customers
SET StartingBalance = StartingBalance - (SELECT SUM(Amount)
FROM #CustomerBalance cb
WHERE Customers.Id = cb.CustomerId);
As you are using an aggregation function, the inner query will give you the sum of all the rows found for the client. And 0 if no row is found.

The aggregate expression cannot be used in the WHERE clause

I have the following tables in my database:
The first table is named Amount, second Product, third Purchase.
And I should to create the trigger on insert to amount table. For example, I'll insert the following values: 4, 1, 10, where 4 is id_purchase, 1 is id_product and 4 is amount of this products. And trigger should subtract this amount from Amount_On_Stock. In my example, it should be: was 48, became 38.
Here's the code of my trigger:
CREATE TRIGGER AmountInsert ON Amount
AFTER INSERT
AS
BEGIN
UPDATE Product
SET Amount_On_Stock = (
SELECT
Amount_On_Stock
FROM Product
WHERE ID_Product = (
SELECT
MAX(ID_Product)
FROM Purchase
WHERE ID_Purchase = (
SELECT
MAX(ID_Purchase)
FROM Purchase
)
)
)-(
SELECT
Amount
FROM AMOUNT
WHERE ID_Product = (
SELECT
MAX(ID_Product)
FROM Purchase
WHERE ID_Purchase = (
SELECT
MAX(ID_Purchase)
FROM Purchase
)
)
)
END
But when I try to create this trigger I have the following error:
The aggregate expression cannot be used in the WHERE clause unless it
is contained in a subquery of the HAVING clause or in the select list,
and the column being aggregated is not an external reference.
So, how can I solve this problem?
Your trigger looks nothing like a SQL Server trigger. I would expect your trigger to look more like this:
CREATE TRIGGER AmountInsert ON Amount AFTER INSERT
AS
BEGIN
UPDATE p
SET Amount_On_Stock = p.Amount_On_Stock - i.amount
FROM Product p JOIN
inserted i
ON p.ID_Product = i.ID_Product;
END;
However, this will not do the right thing if you have multiple inserts on the same product at the same time. To handle that you need aggregation:
CREATE TRIGGER AmountInsert ON Amount AFTER INSERT
AS
BEGIN
UPDATE p
SET Amount_On_Stock = p.Amount_On_Stock - i.amount
FROM Product p JOIN
(SELECT i.ID_Product, SUM(i.amount) as amount
FROM inserted i
GROUP BY i.ID_Product
) i
ON p.ID_Product = i.ID_Product;
END;

Update Table From Select

I am using ms-sql server. I have table which I want to update from select statement. For example the table which I want to update is Table_A with 2 rows in it. The update statement from which I want to update Table_A return 10 rows. So I want to update Table_A 10 times. The problem is that Table_A is updated 2 times(the count of rows in Table_A).
Example:
CREATE TABLE #tmp
(
AccountID INT,
Inflow DECIMAL(10,2)
)
DECLARE #n INT = 0
WHILE (#n <10 )
BEGIN
INSERT INTO #tmp SELECT 2, 10
SET #n += 1
END
UPDATE dbo.Table_A
SET Balance += sss.Inflow
FROM ( SELECT t.AccountID ,
t.Inflow
FROM #tmp AS t
) AS sss
WHERE dbo.tAccount.AccountID = sss.AccountID;
-- Updates only 2 times
-- What I expected here is Table_A to be updated as many times as the count of the select statement which is 10, based on the insert before.
Your expectation is wrong. Admittedly, the documentation buries this idea:
The example runs without error, but each SalesYTD value is updated
with only one sale, regardless of how many sales actually occurred on
that day. This is because a single UPDATE statement never updates the
same row two times.
The documentation continues with the solution:
In the situation in which more than one sale for a specified
salesperson can occur on the same day, all the sales for each sales
person must be aggregated together within the UPDATE statement, as
shown in the following example:
So, simply aggregate before doing the join:
UPDATE dbo.Table_A
SET Balance += sss.Inflow
FROM (SELECT t.AccountID, SUM(t.Inflow) as Inflow
FROM #tmp t
GROUP BY t.AccountId
) sss
WHERE dbo.tAccount.AccountID = sss.AccountID;
Note you can also write this as:
UPDATE a
SET Balance += sss.Inflow
FROM dbo.Table_A a JOIN
(SELECT t.AccountID, SUM(t.Inflow) as Inflow
FROM #tmp t
GROUP BY t.AccountId
) sss
ON a.AccountID = sss.AccountID;
This makes the JOIN more explicit.

SQL Server trigger affect 1 row in a column

I am new to triggers and am having a bit of a problem. I am trying to create a trigger to add the new inserted value of 90 in table sales to the the total sales for id 100 in salesYTD in table internetServices. It seems to do the calculation correctly but it is only suppose to affect the row with the id of 100. Sadly it seems to be changing it for every salesYTD.
CREATE TRIGGER InsertTrigger
ON Sales
AFTER INSERT As
UPDATE InternetServices
SET SalesYTD = (SELECT SUM(Amount)
FROM Sales
WHERE ServiceID = 100)
WHERE ServiceID = 100;
GO
Print 'Master table Before Insert'
Select * From InternetServices
Print 'After Insert'
INSERT INTO Sales VALUES( 11, '2012-11-14' , 90 , 100 );
Select * From InternetServices
Not sure if I gave enough information this is my first time posting a SQL question. Please don't rate down just let me know and I will update it. Thank you.
You need to use INSERTED table. so its add the inserted amount(in table sales) to existing amount in
column SalesYTD of table InternetServices .
CREATE TRIGGER InsertTrigger
ON Sales
AFTER INSERT AS
BEGIN
UPDATE ITS
SET SalesYTD = ITS.Amount + I.Amount
FROM InternetServices ITS
JOIN INSERTED I ON ITS.ID = I.ID
END
GO
You need a where clause for the update, not just in the subquery:
UPDATE InternetServices
SET SalesYTD = (SELECT SUM(Amount)
FROM Sales
WHERE ServiceID = 100
)
WHERE ServiceID = 100;

How to delete the data of old table after transferred to new table in a database in sql insert statement

INSERT INTO Checkout(ProductID, MemberID, Quantity)
SELECT ProductID, MemberID, Quantity FROM Cart WHERE (MemberID = MemberID)
How to use the delete statement to delete the old table data after I transferred to the new table?
DELETE FROM Cart WHERE MemberID = MemberID
Assuming that MemberID is a variable being passed into the query
try
DELETE FROM CART C WHERE
0 < (SELECT COUNT(*) FROM CHECKOUT CO WHERE CO.QUANTITY = C.QUANTITY AND CO.PRODUCTID = C.PRODUCTID AND CO.MEMBERID = C.MEMBERID)
The above removes all rows from CART which are found in CHECKOUT based on the the three columns MEMBERID, PRODUCTID, QUANTITY .
BTW: Any reason you are using WHERE (MemberID = MemberID) ?
IF the second MemberID is a parameter passed into the query I would recommend using a different name for it like pMemberID... IF this is the case you could do DELETE FROM CART WHERE MEMBERID = pMEMBERID .