I have three tables Good Receive header ,Good Receive Details table and stock Table
TB_GoodsReceive_HDR - Header Table
ID SupplierID
1 1
TB_GoodsReceive_DTL - Details Table
ID GR_HDR_ID ItemID WarehouseID ExpiryDate Qty
1 1 1 1 4/4/2012 20
2 1 2 1 4/4/2012 30
TB_Stock - Stock Table
ID ItemID WarehouseID ExpiryDate StockType GR_HDR_ID Qty
1 1 1 4/4/2012 R 1 20
1 2 1 4/4/2012 R 1 30
I have received Item 1 – 20 Qty and Item2 - 30 Qty. Same I have it in my stock table.
There are lot of scenarios , But I need guidelines for this scenario
Now when user updates the TB_GoodsReceive_DTL as below: Updating the item only(ItemID 1 to ItemID 3)
ID GR_HDR_ID ItemID WarehouseID ExpiryDate Qty
1 1 **3** 1 4/4/2012 20
2 1 2 1 4/4/2012 30
My stock table values should be as follows:
ID ItemID WarehouseID ExpiryDate StockType GR_HDR_ID Qty
1 **3** 1 4/4/2012 R 1 20
1 2 1 4/4/2012 R 1 30
But my below stored procedure inserts the new row rather updating the row in the stock master.
Likewise user might update the warehouse or expiry date
The below procedure does the following:
Whenever the goods are received it will check the itemid, warehouse and expirydate in the stock table,if exists it will add the QTY else it will insert the new item in stock table.
The Problem is whenever the Good Receive table is updated(means when user updates ItemId or Expiry Date or Warehouse) how to update the stock table.
Please help me guys, its breaking my head...
Declare
#ItemID int,
#WareHouseID int,
#Qty int,
#StockType nvarchar(30),
#ExpiryDate datetime,
#IsExistsItem int,
#IsExistsWH int,
#IsExistsExpiryDate int,
#IsGR_HDR_ID int,
#GR_HDR_ID int
set #ItemID=1
set #WareHouseID=2
set #Qty=20
set #StockType='R'
set #GR_HDR_ID=2
set #ExpiryDate = '4/4/2012 12:00:00 AM'
set #IsExistsItem = (select count(ItemID) from TB_Stock_Details where
ItemID=#ItemID)
set #IsExistsWH = (select count(WareHouseID) from TB_Stock_Details where
WareHouseID=#WareHouseID)
set #IsExistsExpiryDate = (select count(ExpiryDate) from TB_Stock_Details where
ExpiryDate=#ExpiryDate)
if(#StockType='R')
begin
IF (#IsExistsItem>0) and (#IsExistsWH>0) and (#IsExistsExpiryDate>0)
BEGIN
UPDATE TB_Stock_Details
SET
Qty =Qty + #Qty
WHERE ItemID = #ItemID and GR_HDR_ID = #GR_HDR_ID
END
ELSE
begin
INSERT INTO TB_Stock_Details(ItemID,WareHouseID,Qty,StockType,ExpiryDate)
VALUES(#ItemID,#WareHouseID,#Qty,#StockType,#ExpiryDate)
end
end
First of all after the UPDATE you have two end statements, one is enough.
The reason why the quantity is not increased is because when you insert to the stock details table, you do not set the value for the GR_HDR_ID column. In your update command you set a filter on GR_HDR_ID, but the condition never will be satisfied because it has no value in your table.
edit:
For the scenario you described you need both the old and the new values as parameters, and based on these you can update the stock table too. Without these you cannot know what should be changed, you just get a bunch of new data.
A better alternative for this is to create an update trigger on TB_GoodsReceive_DTL table, in which you have access both the old a new values (inserted and deleted tables) and can update related records in the Stock table.
Related
I want to generate a unique PrescriptionNo for each of the Prescription based on the shopid.
I have tried the following way
id PrescriptionNo Shopid Amount
1 PRES001 2 100
2 PRES002 2 200
3 PRES001 1 100
4 PRES003 2 200
select top 1 'PRES' + right('000' + CAST(ROW_NUMBER() over (order by id) + 1 AS VARCHAR(3)),3)
from prescription
where shopid = 2
order by id desc
Try this:
create table #tmp1 (id int, prescriptionno varchar(10), shopid int, amount int);
insert into #tmp1 values (1,'PRES001',2,100);
insert into #tmp1 values (2,'PRES002',2,200);
insert into #tmp1 values (3,'PRES001',1,100);
insert into #tmp1 values (4,'PRES003',2,200);
select 'PRES' + RIGHT(concat('000',ISNULL(max(right(prescriptionNo,3)),0)+1),3)
from #tmp1
where shopid = 3
=> Returns 'PRES0001'
select 'PRES' + RIGHT(concat('000',ISNULL(max(right(prescriptionNo,3)),0)+1),3)
from #tmp1
where shopid = 2
==> Returns 'PRES0004'
By using just max() allows you to use ISNULL(..,0).
I have these table's:
CREATE TABLE Functions
(
id_f NUMBER (5) NOT NULL,
id_gFK NUMBER (5) NOT NULL
) ;
--id_gFK is foreign key from Salaries table
CREATE TABLE Salaries
(
id_g NUMBER (5) NOT NULL ,
g1_g1 NUMBER (6) ,
g1_g2 NUMBER (6) ,
g1_g3 NUMBER (6) ,
g2_g1 NUMBER (6) ,
g2_g2 NUMBER (6) ,
g2_g3 NUMBER (6) ,
g3_g1 NUMBER (6) ,
g3_g2 NUMBER (6) ,
g3_g3 NUMBER (6)
) ;
--g1_g1 means - grade 1, gradation 1
CREATE TABLE Employee
(
id_e NUMBER (5) NOT NULL ,
id_fFK NUMBER (5) NOT NULL ,
grade NUMBER (1) ,
gradation NUMBER (1) ,
salary NUMBER (6)
) ;
--id_fFK is foreign key from Functions table
When I am inserting an employee, everything is working, and he is taking the salary depending on that column. But, I am able to edit a salary in Salaries table.
For example:
id_g=101, g1_g1=5000....g3_g3=1200 in Salaries table
id_f=201, id_gFK=101 in Functions table
id_e=1001, id_fFK=201, grade=1, gradation=1, salary=5000 in Employee table (5000 was taken from Salaries table depending on id_fFK, grade and gradation).
After I will edit that salary, 5000, in Salaries table, for example, 4000, I want this edit to be done automaticaly in Employee table.
I am sure that I can do this with a trigger. I have tried, but nothing.
Can anyone tell me what kind of trigger I have to use and how?
Thank you!!!
Please see the below example where am updating and inserting a record to emp_sal table and the same is getting inserted to employee table via trigger.
CREATE OR REPLACE TRIGGER change_salary
AFTER INSERT OR UPDATE ON emp_sal
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO Employee (employee_id,first_name,salary)
values (:new.eno,:new.ename,:new.sal);
END IF;
IF UPDATING THEN
UPDATE Employee
SET salary = nvl(:NEW.sal,:old.sal)
WHERE employee_id = :new.eno;
end if;
END;
Execution:
SQL> select sal from emp_sal where eno = 3 ;
SAL
----------
80006
SQL> select salary from employee where employee_id = 3;
SALARY
----------
50000
SQL> update emp_sal
set sal = 1234
where eno = 3 ;
1 row updated.
SQL> commit;
Commit complete.
SQL> select sal from emp_sal where eno = 3 ;
SAL
----------
1234
SQL> select salary from employee where employee_id = 3;
SALARY
----------
1234
SQL> insert into emp_sal(eno,ename,sal)
values
(9,'XING',40000);
1 row created.
SQL> commit;
Commit complete.
SQL> select salary from employee where employee_id =9;
SALARY
----------
40000
EDIT: Am not sure what is your trigger but i do see that there is wrong data set up. I read your requirement and did my way and it working and tested. See below:
Tables with data:
CREATE TABLE Salaries
(
id_g NUMBER (5) NOT NULL PRIMARY KEY ,
g1_g1 NUMBER (6) ,
g1_g2 NUMBER (6) ,
g1_g3 NUMBER (6) ,
g2_g1 NUMBER (6) ,
g2_g2 NUMBER (6) ,
g2_g3 NUMBER (6) ,
g3_g1 NUMBER (6) ,
g3_g2 NUMBER (6) ,
g3_g3 NUMBER (6)
) ;
Insert into SALARIES
Values
(101, 5000, 2000, 3000, 4000,
6000, 7000, 8000, 6000, 12000);
COMMIT;
--------------------------------
CREATE TABLE Functions
(
id_f NUMBER (5) NOT NULL,
id_gFK NUMBER (5) NOT NULL PRIMARY KEY,
CONSTRAINT fk_sal
FOREIGN KEY (id_gFK)
REFERENCES Salaries(id_g)
) ;
Insert into FUNCTIONS
(ID_F, ID_GFK)
Values
(201, 101);
COMMIT;
--------------------------
CREATE TABLE Employees
(
id_e NUMBER (5) NOT NULL ,
id_fFK NUMBER (5) NOT NULL ,
grade NUMBER (1) ,
gradation NUMBER (1) ,
salary NUMBER (6),
CONSTRAINT fk_id_emp
FOREIGN KEY (id_fFK)
REFERENCES Functions(id_gFK)
) ;
Insert into EMPLOYEES
(ID_E, ID_FFK, GRADE, GRADATION, SALARY)
Values
(101, 101, 1, 1, 5000);
COMMIT;
Trigger:
CREATE OR REPLACE TRIGGER change_salary_new
AFTER UPDATE ON Salaries
FOR EACH ROW
BEGIN
UPDATE Employees
SET salary = nvl(:NEW.g1_g1,:old.g1_g1)
WHERE id_e = :new.id_g;
End ;
Execution :
SQL> select id_g,g1_g1 from Salaries;
ID_G G1_G1
---------- ----------
101 5000
SQL> select id_e,salary from Employees;
ID_E SALARY
---------- ----------
101 5000
SQL> update Salaries set g1_g1 = 10202 where id_g = 101;
1 row updated.
SQL> commit;
Commit complete.
SQL> select id_e,salary from Employees;
ID_E SALARY
---------- ----------
101 10202
SELECT it.uid,it.Name,COALESCE(sum(i.Qty),0)-COALESCE(sum(s.Qty),0) as stock
FROM items it
left outer join sales_items s on it.uid=s.ItemID
left outer join inventory i on it.uid=i.uid
group by s.ItemID,i.uid,it.UID;
This is my query. This query take 59 seconds. How can I speed up this query?
my tables ->
items
UID Item
5089 JAM100GMXDFRUT
5090 JAM200GMXDFRUT
5091 JAM500GMXDFRUT
5092 JAM800GMXDFRUT
tables ->
sales_items
- slno ItemID Item Qty
- 9 5089 JAM100GMXDFRUT 5
- 10 5090 JAM200GMXDFRUT 2
- 11 5091 JAM500GMXDFRUT 1
tables ->
inventory
- slno uid Itemname Qty
- 102 5089 JAM100GMXDFRUT 10
- 200 5091 JAM500GMXDFRUT 15
- 205 5092 JAM800GMXDFRUT 20
This table has more than 6000 rows
Put indexes on the join columns
sales_items ItemID
inventory uid
If I was designing something like this I would have a query and schema that looks like this. Take note of my Idx1 indexes. I don't know about MySql but Sql Server will make use of those indexes for the sum function and this is called a covered query.
select Item.ItemID, Item.Name, IsNull(sum(inv.Quantity), 0) - IsNull(sum(s.Quantity), 0) as stock
from Item
Left Join Inventory inv
On Item.ItemID = inv.ItemID
Left Join Sales s
On Item.ItemID = s.ItemID
Group by Item.ItemID, Item.Name
Create Table dbo.Location
(
LocationID int not null identity constraint LocationPK primary key,
Name NVarChar(256) not null
)
Create Table dbo.Item
(
ItemID int not null identity constraint ItemPK primary key,
Name NVarChar(256) not null
);
Create Table dbo.Inventory
(
InventoryID int not null identity constraint InventoryPK primary key,
LocationID int not null constraint InventoryLocationFK references dbo.Location(LocationID),
ItemID int not null constraint InventoryItemFK references dbo.Item(ItemID),
Quantity int not null,
Constraint AK1 Unique(LocationID, ItemID)
);
Create Index InventoryIDX1 on dbo.Inventory(ItemID, Quantity);
Create Table dbo.Sales
(
SaleID int not null identity constraint SalesPK primary key,
ItemID int not null constraint SalesItemFK references dbo.Item(ItemID),
Quantity int not null
);
Create Index SalesIDX1 on dbo.Sales(ItemID, Quantity);
Aside from indexes on the tables to optimize joins, you are also doing a group by of the S.ItemID instead of just using the IT.UID since that is the join basis, and part of the main FROM table of the query... if that is an available index on the items table, use that and you are done. No need to reference the sales_items or inventory column names in the group by.
Now, that being said, another problem you will run into the way you have it is a Cartesian result if you have more than one record for the same "item id" you are summing from sales_items and inventory as I have extremely simplified an example for you via
CREATE TABLE items (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(5) NOT NULL,
PRIMARY KEY (`uid`)
);
CREATE TABLE sales_items (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`itemid` int(11),
`qty` int(5) NOT NULL,
PRIMARY KEY (`sid`),
KEY byItemAndQty (`itemid`,`qty`)
);
CREATE TABLE inventory (
`iid` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`qty` int(5) NOT NULL,
PRIMARY KEY (`iid`),
KEY byItemAndQty (`itemid`,`qty`)
);
insert into items ( uid, name ) values ( 1, 'test' );
INSERT INTO sales_items ( sid, itemid, qty ) VALUES ( 1, 1, 1 );
INSERT INTO sales_items ( sid, itemid, qty ) VALUES ( 2, 1, 2 );
INSERT INTO inventory ( iid, uid, qty ) VALUES ( 1, 1, 13 );
INSERT INTO inventory ( iid, uid, qty ) VALUES ( 2, 1, 35 );
Simple 1 item,
Sales items 2 records for Item 1.. Qty of 1 and 2, total = 3
Inventory 2 records for Item 1.. Qty of 13 and 35, total 38
SELECT
it.uid,
it.Name,
sum(i.Qty) as iQty,
sum(s.Qty) as sQty,
COALESCE( sum(i.Qty),0) - COALESCE(sum(s.Qty),0) as stock
FROM
items it
left outer join sales_items s
on it.uid = s.ItemID
left outer join inventory i
on it.uid = i.uid
group by
it.uid
So, the result of the query you MIGHT EXPECT the Stock to be
uid name iQty sQty stock
1 test 48 3 45
but in reality becomes
1 test 96 6 90
NOW... PLEASE TAKE NOTE OF MY ASSUMPTION, but see similar sum()s or count()s from multiple tables like this. I am assuming the ITEMS table is one record per item.
The Sales_Items actually has more columns than provided (such as sales details and every date/sales count could be tracked) and MAY CONTAIN Multiple sales record quantities for a given item id (thus matching my sample).. Finally, the Inventory table similarly could have more than one record per same item, such as purchases of incoming inventory tracked by date and thus multiple records per a given item id (also matching my example).
To prevent this type of Cartesian result, and can also increase speed, I would do pre-aggregates per secondary table and join to that.
SELECT
it.uid,
it.Name,
i.iQty,
s.sQty,
COALESCE( i.iQty,0) - COALESCE(s.sQty,0) as stock
FROM
items it
left join ( select itemid, sum( qty ) as SQty
from sales_items
group by itemid ) s
on it.uid = s.ItemID
left join ( select uid, sum( qty ) as IQty
from inventory
group by uid ) i
on it.uid = i.uid
group by
it.uid
And you get the correct values of
uid name iQty sQty stock
1 test 48 3 45
Yes, this was only for a single item ID to prove the point, but still applies to as many inventory items as you have and respective sales/inventory records that may (or not) exist for certain items.
once there are new data insert to my DB my rcount will increase by 1, what am i trying to do is to display latest inserted record to users, but i cant get my expected result
rCount in my datebase
1
2
3
4
5
output
5
4
3
1
2
expected output
5
4
3
2
1
"SELECT *, ROW_NUMBER() OVER (ORDER BY rCount DESC) AS 'RowNumber'
FROM [MovieListTable]"
Instead of using the row number you should introduce a numeric primary key (i.e. Id) and make it an Identity column. Now you can just select the row that has the maximum Id value:
select top 1 * from MovieListTable order by Id desc
Or to get all rows:
select * from MovieListTable order by Id desc
I am using c# and SQL Server 2008.
I have table like this
id | propertyTypeId | FinishingQualityId | title | Description | features
1 1 2 prop1 propDEsc1 1,3,5,7
2 2 3 prop2 propDEsc2 1,3
3 6 5 prop3 propDEsc3 1
4 5 4 prop4 propDEsc4 3,5
5 4 6 prop5 propDEsc5 5,7
6 4 6 prop6 propDEsc6
and here is my stored code (search in the same table)
create stored procdures propertySearch
as
#Id int = null,
#pageSize float ,
#pageIndex int,
#totalpageCount int output,
#title nvarchar(150) =null ,
#propertyTypeid int = null ,
#finishingqualityid int = null ,
#features nvarchar(max) = null , -- this parameter send like 1,3 ( for example)
begin
select
row_number () as TempId over( order by id) ,
id, title, description,
propertyTypeId, propertyType.name,
finishingQualityId, finishingQuality.Name,
freatures
into #TempTable from property
join propertyType on propertyType.id= property.propertyTypeId
join finishingQuality on finishingQuality.id = property.finishingQualityId
where
property.id = isnull(#id,property.id ) and proprty.PropertyTypeId= isnull(#propertyTypeid,property.propertyTypeId)
select totalpageconunt = ((select count(*) from #TempTable )/#pageSize )
select * from #TempTable where tempid between (#pageindex-1)*#pagesize +1 and (#pageindex*#pageSize)
end
go
I can't here filter the table by feature I sent. This table has too many rows I want to add to this stored code to filter data for example when I send 1,3 in features parameter I want to return row number one and two in the example table I write in this post (want to get the data from table must have the feature I send)
Many thanks for every one helped me and will help
Sending a delimited list of values to match with a delimited value in a column will generally get you into trouble as the only way to do it is to split each value out from the string. (Also why indexing them is pointless)
You should create an additional table containing the id from your property table & a row for each feature;
property_id feature
----------- -------
5 5
5 7
Then matching is much simpler. You can send the procedure the list of features you want to match ideally using a table valued parameter or alternatively a table function.