Insert current row number into SQL Server table - sql-server

I have the following table in SQL Server:
CREATE TABLE [dbo].[tblTempPo](
[TempPoID] [int] IDENTITY(1,1) NOT NULL,
[guid] AS ([dbo].[GetIdentity]()),
[Qty] [int] NULL,
[MobileBrandID] [int] NULL,
[MobileID] [int] NULL
)
I need to insert the current row number to the guid column every time a new row is added. I tried to use the following function but it's not working as expected:
ALTER FUNCTION GetIdentity()
RETURNS INT AS
BEGIN
RETURN (SELECT top 1 ROW_NUMBER() OVER(ORDER BY TempPoID asc)FROM tblTempPo)
END

Your function GetIdentity() will probably always return 1 but it is not a sure thing because you are using select top 1... without an order by clause.
If you want the highest value returned by row_number() you need to add order by 1 desc which would be the same as doing SELECT count(*) from tblTempPo.
Fixing GetIdentity() like that will not help much in your situation because [guid] AS ([dbo].[GetIdentity]()) will give you a computed column that is evaluated every time you query the table and not when you insert a new row. You will always have the same value for all rows.
You could use a function that takes the TempPoID as a parameter as a computed column.
CREATE FUNCTION GetIdentity(#P int)
RETURNS INT AS
BEGIN
RETURN (SELECT rn
FROM (SELECT TempPoID,
ROW_NUMBER() OVER(ORDER BY TempPoID ASC) AS rn
FROM tblTempPo) AS T
WHERE TempPoID = #P)
END
Table definition:
CREATE TABLE [dbo].[tblTempPo](
[TempPoID] [int] IDENTITY(1,1) NOT NULL primary key,
[guid] as dbo.GetIdentity(TempPoID),
[Qty] [int] NULL,
[MobileBrandID] [int] NULL,
[MobileID] [int] NULL
I have never used this so I can't tell you if it is a good thing to do or not. It might be devastating for your query performance, I just don't know.

I agree with comments and you should change the GUID column name. If you really have to store the TempPoID column twice use computed column. Example:
CREATE TABLE #tblTempPo (
[TempPoID] [int] IDENTITY(1,1) NOT NULL,
[second_id] AS TempPoID,
[Qty] [int] NULL,
[MobileBrandID] [int] NULL,
[MobileID] [int] NULL
)
INSERT INTO #tblTempPo (Qty, MobileBrandID, MobileID) VALUES
(10, 10, 15), (20, 23, 45), (55, 23, 12), (10, 1, 1)
SELECT * FROM #tblTempPo
DROP TABLE #tblTempPo
If you need more complicated approach - use trigger.

It's all no good idea, but if you REALLY need it, try trigger:
create table [dbo].[tblTempPo](
[TempPoID] [int] identity(1,1) NOT NULL,
[guid] int,
[Qty] [int] NULL,
[MobileBrandID] [int] NULL,
[MobileID] [int] NULL
)
go
create trigger [dbo].[tblTempPo_Trig] on [dbo].[tblTempPo] instead of insert as
declare #cnt int
select #cnt = count(*)
from [dbo].[tblTempPo] with(nolock)
insert into [dbo].[tblTempPo]([guid], [Qty], [MobileBrandID], [MobileID])
select #cnt+row_number() over (order by [TempPoID]), [Qty], [MobileBrandID], [MobileID] from inserted
go
insert into [dbo].[tblTempPo]([Qty], [MobileBrandID], [MobileID]) values (0, 0,0), (0, 0,0), (0, 0,0), (0, 0,0)
insert into [dbo].[tblTempPo]([Qty], [MobileBrandID], [MobileID]) values (0, 0,0), (0, 0,0), (0, 0,0), (0, 0,0)
select * from [dbo].[tblTempPo]
go
drop table [dbo].[tblTempPo]
go

Related

How to calculate running total from due amount in SQL Server

I have customer Table ID and Customer Name
CREATE TABLE [dbo].[Customer]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [nvarchar](500) NULL
) ON [PRIMARY]
I have Payment Schedule Table each customer may have different schedule
CREATE TABLE [dbo].[SchedulePayment]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Date] [date] NULL,
[Amount] [decimal](18, 0) NULL,
[CustomerID] [int] NULL
) ON [PRIMARY]
I have ReceivedPayment table:
CREATE TABLE [dbo].[ReceivedPayment]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[CustomerID] [int] NULL,
[ReceivedAmount] [decimal](18, 0) NULL,
[ReceivedDate] [date] NULL
) ON [PRIMARY]
I want to deduct received amount from the schedule amount and show the remaining amount till today month and year future amount would be 0 because it is not due now but if customer pay extra then it will show in the future months
I want below output
SELECT rp.CustomerID,[date] ScheduleDate, ReceivedAmount,
(SumAmount -
SUM(ReceivedAmount)
OVER (PARTITION BY rp.CustomerID ORDER BY Receiveddate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
) AS PendingAmount
,Amount AS ScheduleAmount
FROM
(SELECT [date], Amount, CustomerID,
(SUM(amount)
OVER (PARTITION BY CustomerID ORDER BY [date] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
) AS SumAmount
FROM SchedulePayment) sp
JOIN ReceivedPayment rp ON rp.CustomerID = sp.CustomerID
AND ReceivedDate >= [date]
AND
(
(DATEPART(MM,ReceivedDate)=DATEPART(MM,[date]))
AND (DATEPART(YYYY,ReceivedDate)=DATEPART(YYYY,[date]))
)
ORDER BY rp.CustomerID,ReceivedDate,[date]
i looked at it too, and there is more going on here than can be explained at first glance. in normal payment posting, a balance carry forward rule to be held pending apply, and another rule would exist as the first of the month occurs, for payments in excess of payment due let alone no arrears. the solution has some rules than in all intense purposes is not necessarily database driven yet process and application driven from an accounting a/r perspective. here is some sample testing I did just to see how close I could come yet then realized expected output requires rules and dates and what I call float.
use test1
/*
CREATE TABLE [dbo].[Customer]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [nvarchar](500) NULL
) ON [PRIMARY]
-- drop table customer
insert into customer select ('Customer1')
insert into customer select ('Customer2')
select * from customer
CREATE TABLE [dbo].[SchedulePayment]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Date] [date] NULL,
[Amount] money NULL,
[CustomerID] [int] NULL
) ON [PRIMARY]
insert into SchedulePayment values ('2022-01-01', 1000, 1)
insert into SchedulePayment values ('2022-02-01', 1000, 1)
insert into SchedulePayment values ('2022-03-01', 1000, 1)
insert into SchedulePayment values ('2022-04-01', 1000, 1)
insert into SchedulePayment values ('2022-01-01', 1000, 2)
insert into SchedulePayment values ('2022-02-01', 1000, 2)
insert into SchedulePayment values ('2022-03-01', 1000, 2)
insert into SchedulePayment values ('2022-04-01', 1000, 2)
-- drop table schedulepayment
select * from schedulepayment
CREATE TABLE [dbo].[ReceivedPayment]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[CustomerID] [int] NULL,
[ReceivedAmount] money NULL,
[ReceivedDate] [date] NULL
) ON [PRIMARY]
insert into ReceivedPayment values (1, 500, '2022-01-06')
insert into ReceivedPayment values (1, 1500, '2022-02-15')
insert into ReceivedPayment values (1, 500, '2022-03-10')
insert into ReceivedPayment values (2, 100, '2022-01-01')
insert into ReceivedPayment values (2, 500, '2022-02-06')
insert into ReceivedPayment values (2, 400, '2022-02-08')
insert into ReceivedPayment values (2, 600, '2022-03-04')
-- drop table receivedpayment
select * from receivedpayment
*/
create table #t
(CustomerID int,
ScheduleDate date,
ReceivedAmount money,
PendingAmount money,
ScheduledAmount money
)
insert into #t (customerid, scheduledate, scheduledamount)
select
distinct customer.ID,
schedulepayment.date,
schedulepayment.Amount
from customer
left join schedulepayment on SchedulePayment.CustomerID = customer.ID
select * from #t
drop table #t
-- below is a pay flow by yet not a balance over paid and carry over to be spread
select
SchedulePayment.CustomerID,
SchedulePayment.Date,
ReceivedAmount = sum(ReceivedPayment.ReceivedAmount)
from ReceivedPayment
join SchedulePayment on ReceivedPayment.CustomerID = SchedulePayment.CustomerID
where datepart(month, SchedulePayment.Date) = datepart(month, ReceivedPayment.ReceivedDate) and datepart(year, schedulepayment.Date) = datepart(year, ReceivedPayment.ReceivedDate)
GROUP BY SchedulePayment.CustomerID, SchedulePayment.Date

After insert trigger doesn't work when using Inserted

I'm trying to write a trigger on my Employees table that should not allow the insertion of a new employee that has a hire date that is older than the hire date of his boss
CREATE TABLE [dbo].[Employees]
(
[EID] [int] IDENTITY(1,1) NOT NULL,
[Ename] [nvarchar](20) NOT NULL,
[Gender] [nvarchar](1) NOT NULL,
[IsMarried] [nvarchar](1) NOT NULL,
[Birthdate] [date] NOT NULL,
[HireDate] [date] NOT NULL,
[Salary] [float] NOT NULL,
[Notes] [nvarchar](200) NULL,
[NationalityID] [int] NULL,
[BossID] [int] NULL,
CONSTRAINT [PK_Employees]
PRIMARY KEY CLUSTERED ()
)
And here's the trigger code:
CREATE TRIGGER [dbo].[Trig_04]
ON [dbo].[Employees]
AFTER INSERT
AS
BEGIN
IF ((SELECT INSERTED.HireDate FROM INSERTED WHERE BossID <> EID) <
(SELECT Employees.HireDate FROM Employees
WHERE EID IN (SELECT Employees.BossID FROM Employees WHERE BossID <> EID)))
ROLLBACK
END
It executes normally (no errors) but it just doesn't work, but when I was using the employees table in the subquery instead of the inserted table, it was working normally. Does anyone have an answer for this?
You have to write triggers in SQL Server to handle the fact that INSERTED could contain multiple records. You cannot assume it will only be a single record. I think the following is what you are looking for:
if exists (
select 1
from Inserted I
where I.BossID <> I.EID
and I.HireDate < (select E.HireDate from Employees E where E.EID = I.BossID)
) begin
ROLLBACK;
end

Compare two child table items with two similar parent tables from two databases

I need help creating a query to compare the Equipment in one database to Asset in another table. Here is my database setup:
CREATE DATABASE database1
GO
USE [database1]
GO
CREATE TABLE [dbo].[Application]
(
[ApplicationID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[APP_NUMBRER] [int] NULL,
)
GO
CREATE TABLE [dbo].[Equipment]
(
[EquipID] [int] IDENTITY(1,1) NOT NULL,
[ApplicationID] [int] NULL,
[Year] [varchar](4) NULL,
[Make] [varchar](50) NULL,
[Model] [varchar](50) NULL
)
ALTER TABLE [dbo].[Equipment] WITH CHECK
ADD CONSTRAINT [FK_EQUIP_1]
FOREIGN KEY([ApplicationID]) REFERENCES [dbo].[APPLICATION] ([ApplicationID])
GO
INSERT INTO [Application]
VALUES (1), (2), (3)
INSERT INTO [Equipment]
VALUES (1, '1998', 'Equip1', 'Model1'),
(1, '1855', 'Equip2', 'Model2'),
(2, '1222', 'Equip3', 'Model4'),
(2, '1333', 'Equip4', 'Model4'),
(3, '1777', 'Equip5', 'Model5')
GO
CREATE DATABASE database2
GO
USE [database2]
GO
CREATE TABLE [dbo].[Application]
(
[APP_KEY] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[APP_DESCRIPTION] [varchar](40) NOT NULL
)
GO
CREATE TABLE [dbo].[ASSET]
(
[AS_KEY] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[AS_APP_FKEY] [int] NOT NULL,
[Year] [varchar](4) NULL,
[Make] [varchar](50) NULL,
[Model] [varchar](50) NULL
)
ALTER TABLE [dbo].[ASSET] WITH CHECK
ADD CONSTRAINT [FK_ASSET_1]
FOREIGN KEY([AS_APP_FKEY]) REFERENCES [dbo].[APPLICATION] ([APP_KEY])
GO
INSERT INTO [Application]
VALUES ('AppDesc1'), ('AppDesc2')
INSERT INTO [ASSET]
VALUES (1, '1998', 'Asset1', 'Db2Model1'),
(1, '1855', 'Asset2', 'Db2Model2'),
(2, '1222', 'Asset3', 'Db2Model3'),
(2, '1333', 'Asset4', 'Db2Model4')
GO
My query:
SELECT
ap1.APP_NUMBRER,
e.Year, e.Make, e.Model,
db2.APP_KEY, db2.Year, db2.Make, db2.Model
FROM
database1.dbo.Application ap1
JOIN
database1.dbo.Equipment e ON E.APPLICATIONID = ap1.APPLICATIONID
LEFT JOIN
(SELECT
APP_KEY, Year, Make, Model
FROM
[database2].dbo.APPLICATION ap2
JOIN
[database2].dbo.ASSET ON asset.AS_APP_FKEY = ap2.APP_KEY) db2 ON ap1.APP_NUMBRER = db2.APP_KEY
Result:
Expected result: my query is creating a few duplicate items that compare all of db1 equipment to db2 assets. I want a one to one comparison. I don't want items 2,3,6,7. Is this because of how the table relationships are set up.
It's because you're only joining on APP_NUMBER=APP_KEY. Add Year=Year to the JOIN and you will get your desired result.
Add YEAR in you join. It will solve your problem.
SELECT ap1.APP_NUMBRER, e.Year, e.Make, e.Model, db2.APP_KEY, db2.Year, db2.Make, db2.Model
FROM database1.dbo.Application ap1
JOIN database1.dbo.Equipment e
ON E.APPLICATIONID = ap1.APPLICATIONID
LEFT JOIN(
SELECT APP_KEY, Year, Make, Model
FROM [database2].dbo.APPLICATION ap2
JOIN [database2].dbo.ASSET
ON asset.AS_APP_FKEY = ap2.APP_KEY
) db2
ON ap1.APP_NUMBRER = db2.APP_KEY AND e.Year = db2.Year
Amend your JOIN condition like so
db2 ON ap1.APP_NUMBRER = db2.APP_KEY
AND e.Year = db2.Year

Read data from another columns to current table in SQL

I have these tables :
CREATE TABLE [dbo].[FileISOManagers]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[LineId] [int] NOT NULL,
[Revision] [nvarchar](max) NULL,
[FileName] [nvarchar](max) NULL,
[UserId] [int] NOT NULL,
[SubmitDateTime] [datetime] NOT NULL
)
CREATE TABLE [dbo].[Lines]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[LineNumber] [nvarchar](max) NULL,
[DocumentNumber] [nvarchar](max) NULL,
[Revision] [nvarchar](max) NULL
)
Every line has multiple revisions, so I just need to insert the last revision column value in FileISOManagers table inside Revision column in lines table automatically. I want do this in SQL Server. Is there any solution to do this? Should I use a trigger?
revision
-- Create trigger on table FileISOManagers for Insert statement
CREATE TRIGGER trgAfterInsert on FileISOManagers
FOR INSERT
AS declare #Revision varchar(100);
select #Revision=i.Revision from inserted i;
set #action='Inserted Record -- After Insert Trigger.'; insert into Lines(Revision)
values (#Revision);
PRINT 'AFTER INSERT trigger fired.
It can be done using joins and alias.
Example
INSERT INTO FileISOManagers (Revision ..columns)
SELECT *
FROM Lines ls
WHERE NOT EXISTS
(
SELECT *
FROM FileISOManagers
WHERE LineId = ls.id
) order by ls.id desc

How to generate a unique ID for every insert statement in SQL Server?

I want to give a unique ID for every insert statement I make, this is so I can see what rows was inserted together. I prefer that the unique "insert ID" start at 1 and increases by one like the IDENTITY(1,1) for rows.
Is there a easy way like IDENTITY to do that?
CREATE TABLE [dbo].[factTrade]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[insertedID] [int] NOT NULL,
[quantity] [int] NOT NULL,
[price] [decimal](20, 10) NOT NULL
)
INSERT INTO [dbo].[factTrade] ([insertedID], [quantity], [price])
VALUES (1, 6, 2.5), (1, 4, 3.7), (1, 3, 4.1), (1, 7, 8.5),
INSERT INTO [dbo].[factTrade] ([insertedID], [quantity], [price])
VALUES (2, 5, 5.2), (2, 1, 4.6)
This isn't the solution you asked for, but you could add a column with a default timestamp to find all rows inserted at the same time.
ALTER TABLE dbo.factTrade
ADD InsertDate DATETIME NOT NULL DEFAULT (GETDATE())
Guids are handy for things like that.
declare #insertid uniqueidentifier = newid();
CREATE TABLE [dbo].[factTrade](
[ID] [int] IDENTITY(1,1) NOT NULL,
[insertedID] [int] NOT NULL,
[quantity] [int] NOT NULL,
[price] [decimal](20, 10) NOT NULL,
[insertid] [uniqueidentifier] not null
)
INSERT INTO [dbo].[factTrade]
([insertedID]
,[quantity]
,[price]
,[insertid]
)
VALUES
(1, 6, 2.5,#insertid),
(1, 4, 3.7,#insertid),
(1, 3, 4.1,#insertid),
(1, 7, 8.5,#insertid)
set #insertid = newid(); --get another guid
INSERT INTO [dbo].[factTrade]
([insertedID]
,[quantity]
,[price]
,[insertid]
)
VALUES
(2, 5, 5.2,#insertid),
(2, 1, 4.6,#insertid)
If you need an integer value, then you can create another table:
CREATE TABLE inserts ([ID] INT IDENTITY(1,1)...)
Then from your app, insert a row into this, then use the generated identity value (SCOPE_IDENTITY()).
INSERT inserts DEFAULT VALUES;
SELECT #insertId = SCOPE_IDENTITY();
This is what I ended up doing, thank you for all the suggestions and comments.
DECLARE #insertedID INT
CREATE TABLE [dbo].[factTrade]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[insertedID] [int] NOT NULL,
[quantity] [int] NOT NULL,
[price] [decimal](20, 10) NOT NULL
)
CREATE SEQUENCE [dbo].[factTradeInsertedID] AS INT
START WITH 1
INCREMENT BY 1
SET #insertedID = NEXT VALUE FOR [dbo].[factTradeInsertedID] --1
INSERT INTO [dbo].[factTrade]
([insertedID]
,[quantity]
,[price])
VALUES
(#insertedID, 6, 2.5)
,(#insertedID, 4, 3.7)
,(#insertedID, 3, 4.1)
,(#insertedID, 7, 8.5)
SET #insertedID = NEXT VALUE FOR [dbo].[factTradeInsertedID] --2
INSERT INTO [dbo].[factTrade]
([insertedID]
,[quantity]
,[price])
VALUES
(#insertedID, 5, 5.2)
,(#insertedID, 1, 4.6)

Resources