SQL Moving Row to Identical Table WITHOUT auto-increment (SQL Server 2008) - sql

I have two tables - "RENTED" and "HISTORY." Once an item is returned I need to move it to the "HISTORY" table using a procedure. The tables are identical in every way. The primary key is just a number, but is NOT auto-incremented. When I try to move a row from Rented to History, I get a clash because the primary keys both have the number 2 for an ID number. I know I just need to find the max value of the primary key in the HISTORY table, then add the row after. Seemed easy, ended up being hard to do. Lastly, I delete the row from the RENTED Table, which I am able to do. Please assist me with the row movement. Thanks!
Also, I looked at some other similar code samples/answers here, but didn't find a solution quite yet.
Create Procedure spMoveToHistory
#RENTED_OUT_NUM bigint
AS
Begin
Insert Into HISTORY
Select *
From RENTED_OUT
Where RENTED_OUT_NUM = #RENTED_OUT_NUM
Select #RENTED_OUT_NUM = (MAX(HISTORY_NUM)+1)
From HISTORY
Delete From RENTED
Where RENTED_OUT_NUM = #RENTED_OUT_NUM
End
So in this procedure, I just want to enter the number 2 and take the 2nd record in the RENTED table and move over to the HISTORY table's next available row. See below for better visualization of the tables (a few columns omitted)
**RENTED TABLE:**
RENTED_OUT_ID (PK) | ITEM_NAME | ITEM_DESC | DATE_RENTED | DATE_RETURNED
1 data data data data
2 move this data data data data
3 data data data data
**HISTORY TABLE:**
HISTORY_NUM (PK) | ITEM_NAME | ITEM_DESC | DATE_RENTED | DATE_RETURNED
1 data data data data
2 data data data data
-> INSERT HERE

You can use the OUTPUT INTO clause to insert the deleted record into the history table in one go. The syntax will be this:
declare #max_id bigint
select #max_id = max(HISTORY_NUM)+1 from history
DELETE FROM rented
OUTPUT #max_id
, DELETED.ITEM_NAME
, DELETED.ITEM_DESC
, DELETED.DATE_RENTED
, DELETED.DATE_RETURNED
INTO history
WHERE RENTED_OUT_NUM = #RENTED_OUT_NUM

The problem is occurring while inserting in HISTORY_NUM column of HISTORY table because its a primary key and cannot take repetitive value of RENTED_OUT_ID column of RENTED table.
So find max existing HISTORY_NUM column value and increment by one to insert new record every time while moving records.
Create Procedure spMoveToHistory
#RENTED_OUT_NUM bigint
AS
Begin
DECLARE #HISTORY_ID BIGINT
SELECT #HISTORY_ID = MAX(HISTORY_NUM) FROM HISTORY
Insert Into HISTORY(HISTORY_NUM, ITEM_NAME, ITEM_DESC, DATE_RENTED, DATE_RETURNED)
Select #HISTORY_ID + 1 , ITEM_NAME, ITEM_DESC, DATE_RENTED, DATE_RETURNED
From RENTED_OUT
Where RENTED_OUT_ID = #RENTED_OUT_NUM
Delete From RENTED
Where RENTED_OUT_NUM = #RENTED_OUT_NUM
End

Related

Adding column to sqlite database and distribute rows based on primary key

I have some data elements containing a timestamp and information about Item X sales related to this timestamp.
e.g.
timestamp | items X sold
------------------------
1 | 10
4 | 40
7 | 20
I store this data in an SQLite table. Now I want to add to this table. Especially if I get data about another item Y.
The item Y data might or might not have different timestamps but I want to insert this data into the existing table so that it looks like this:
timestamp | items X sold | items Y sold
------------------------------------------
1 | 10 | 5
2 | NULL | 10
4 | 40 | NULL
5 | NULL | 3
7 | 20 | NULL
Later on additional sales data (columns) must be added with the same scheme.
Is there an easy way to accomplish this with SQLite?
In the end I want to fetch data by timestamp and get an overview which items were sold at this time. Most examples consider the usecase to add a complete row (one record) or a complete column if it perfectly matches to the other columns.
Or is sqlite the wrong tool at all? And I should rather use csv or excel?
(Using pythons sqlite3 package to create and manipulate the DB)
Thanks!
Dynamically adding columns is not a good design. You could add them using
ALTER TABLE your_table ADD COLUMN the_column_name TEXT
the column, for existing rows would be populated with nulls, although you could specify a DEFAULT value and the existing rows would then be populated with that value.
e.g. the following demonstrates the above :-
DROP TABLE IF EXISTS soldv1;
CREATE TABLE IF NOT EXISTS soldv1 (timestamp INTEGER PRIAMRY KEY, items_sold_x INTEGER);
INSERT INTO soldv1 VALUES(1,10),(4,40),(7,20);
SELECT * FROM soldv1 ORDER BY timestamp;
ALTER TABLE soldv1 ADD COLUMN items_sold_y INTEGER;
UPDATE soldv1 SET items_sold_y = 5 WHERE timestamp = 1;
INSERT INTO soldv1 VALUES(2,null,10),(5,null,3);
SELECT * FROM soldv1 ORDER BY timestamp;
resulting in the first query returning :-
and the second query returning :-
However, as stated, the above is not considered a good design as the schema is dynamic.
You could alternately manage an equivalent of the above with the addition of either a new column (to also be part of the primary key) or by prefixing/suffixing the timestamp with a type.
Consider, as an example, the following :-
DROP TABLE IF EXISTS soldv2;
CREATE TABLE IF NOT EXISTS soldv2 (type TEXT, timestamp INTEGER, items_sold INTEGER, PRIMARY KEY(timestamp,type));
INSERT INTO soldv2 VALUES('x',1,10),('x',4,40),('x',7,20);
INSERT INTO soldv2 VALUES('y',1,5),('y',2,10),('y',5,3);
INSERT INTO soldv2 VALUES('z',1,15),('z',2,5),('z',9,25);
SELECT * FROM soldv2 ORDER BY timestamp;
This has replicated, data-wise, your original data and additionally added another type (column items_sold_z) without having to change the table's schema (nor having the additional complication of needing to update rather than insert as per when applying timestamp 1 items_sold_y 5).
The result from the query being :-
Or is sqlite the wrong tool at all? And I should rather use csv or excel?
SQLite is a valid tool. What you then do with the data can probably be done as easy as in excel (perhaps simpler) and probably much simpler than trying to process the data in csv format.
For example, say you wanted the total items sold per timestamp and how many types were sold then :-
SELECT timestamp, count(items_sold) AS number_of_item_types_sold, sum(items_sold) AS total_sold FROM soldv2 GROUP by timestamp ORDER BY timestamp;
would result in :-

Checking if ID exists and also if another column is null and updating another column

I am about to implement an update statement on a table. I know it sounds really simple, but I'm not able to get through it logically.
Scenario:
There is a table I have with the below format, that gets data everyday through a process. The columns on the table are as follows:
PKID | RecordID | ThirdPartyID | Action | DATEADDED
PKID: The auto incremental Primary Key.
RecordID: Can have duplicates.
ThirdpartyID: Can be multiple values and also accepts NULLS.
Action: The column that needs to be updated
DateAdded: Contains the GETDATE() of when the record is imported into the table.
Problem:
There is a process that imports new records into this table everyday. When the records are inserted for a day, I need to check the following:
Check if the newly Inserted RecordIDs are already existing in the table.
If the RecordID entered today, is already there in the table (there can be multiple entries of the same RecordID in the old records),
Check if the ThirdPartyID is NULL in the old records for that RecordID.
If the ThirdPartyID exists in any of the old records for that RecordID, update the Action Column with 'Multiple Entries.'
Else do nothing.
Please let me know if I can provide any further clarification or details in this regard.
I would approach the problem like this:
Load new data into a Temp table.
Inner Join the 2 tables on RecordID which will join only if the RecordID exists in both tables...
update the Action column to "Multiple Entries" if the ThirdPartyID field is also null.
Script should be something like this:
UPDATE Main
SET Action = 'Multiple Entries'
FROM Main INNER JOIN Temp ON Main.RecordID = Temp.RecordID
WHERE Main.ThirdPartyID IS NOT NULL
You could get a copy of the inserted data by OUTPUT-ing it to a table variable, then perform the update by joining to the original table. e.g:
DECLARE #inserted TABLE
(PKID INT
,RecordID INT
,ThirdPartyID INT
,Action VARCHAR(MAX)
,DateAdded DATE);
INSERT TestTable1
(RecordID
,ThirdPartyID
,Action
,DateAdded)
OUTPUT
inserted.PKID
,inserted.RecordID
,inserted.ThirdPartyID
,inserted.Action
,inserted.DateAdded
INTO #inserted
(PKID
,RecordID
,ThirdPartyID
,Action
,DateAdded)
VALUES
(1
,2
,NULL
,GETDATE());
UPDATE t
SET ThirdPartyID = 'Multiple Entries'
FROM #inserted i
JOIN TestTable1 t
ON i.RecordID = t.RecordID
WHERE t.ThirdPartyID IS NOT NULL;

How to update rows in one column of a Table with increment number in minus in Sybase ASE

I have to update around 40 rows in a column of a table with increment of numbers in minus i.e -1,-2,-3,-4 etc in sybase ASE. Can any one tell how to do
Raj, identity values in ASE cannot be set to maintain a sequence of negative values as you want. So that eliminates the simplest approach.
Let's assume your table looks like this:
CREATE TABLE cars (
id not null,
name varchar(20),
serial int null
)
where serial is the column that may contain NULL values.
You could create a trigger on the table to update serial when it is null.
Alternatively if you are trying to update existing values in this table you could run the following code 40 times:
UPDATE cars
SET serial = -(SELECT COUNT(*) FROM cars WHERE serial IS NULL)
WHERE id = (SELECT MAX(id) FROM cars WHERE serial IS NULL)
Of course, for 40 rows manually updating the values sounds attractive!

SQL - keep values with UPDATE statement

I have a table "news" with 10 rows and cols (uid, id, registered_users, ....) Now i have users that can log in to my website (every registered user has a user id). The user can subscribe to a news on my website.
In SQL that means: I need to select the table "news" and the row with the uid (from the news) and insert the user id (from the current user) to the column "registered_users".
INSERT INTO news (registered_users)
VALUES (user_id)
The INSERT statement has NO WHERE clause so i need the UPDATE clause.
UPDATE news
SET registered_users=user_id
WHERE uid=post_news_uid
But if more than one users subscribe to the same news the old user id in "registered_users" is lost....
Is there a way to keep the current values after an sql UPDATE statement?
I use PHP (mysql). The goal is this:
table "news" row 5 (uid) column "registered_users" (22,33,45)
--- 3 users have subscribed to the news with the uid 5
table "news" row 7 (uid) column "registered_users" (21,39)
--- 2 users have subscribed to the news with the uid 7
It sounds like you are asking to insert a new user, to change a row in news from:
5 22,33
and then user 45 signs up, and you get:
5 22,33,45
If I don't understand, let me know. The rest of this solution is an excoriation of this approach.
This is a bad, bad, bad way to store data. Relational databases are designed around tables that have rows and columns. Lists should be represented as multiple rows in a table, and not as string concatenated values. This is all the worse, when you have an integer id and the data structure has to convert the integer to a string.
The right way is to introduce a table, say NewsUsers, such as:
create table NewsUsers (
NewsUserId int identity(1, 1) primary key,
NewsId int not null,
UserId int not null,
CreatedAt datetime default getdaete(),
CreatedBy varchar(255) default sysname
);
I showed this syntax using SQL Server. The column NewsUserId is an auto-incrementing primary key for this table. The columns NewsId is the news item (5 in your first example). The column UserId is the user id that signed up. The columns CreatedAt and CreatedBy are handy columns that I put in almost all my tables.
With this structure, you would handle your problem by doing:
insert into NewsUsers
select 5, <userid>;
You should create an additional table to map users to news they have registeres on
like:
create table user_news (user_id int, news_id int);
that looks like
----------------
| News | Users|
----------------
| 5 | 22 |
| 5 | 33 |
| 5 | 45 |
| 7 | 21 |
| ... | ... |
----------------
Then you can use multiple queries to first retrieve the news_id and the user_id and store them inside variables depending on what language you use and then insert them into the user_news.
The advantage is, that finding all users of a news is much faster, because you don't have to parse every single idstring "(22, 33, 45)"
It sounds like you want to INSERT with a SELECT statement - INSERT with SELECT
Example:
INSERT INTO tbl_temp2 (fld_id)
SELECT tbl_temp1.fld_order_id
FROM tbl_temp1
WHERE tbl_temp1.fld_order_id > 100;

Retrieve inserted row ID in SQL

How do I retrieve the ID of an inserted row in SQL?
Users Table:
Column | Type
--------|--------------------------------
ID | * Auto-incrementing primary key
Name |
Age |
Query Sample:
insert into users (Name, Age) values ('charuka',12)
In MySQL:
SELECT LAST_INSERT_ID();
In SQL Server:
SELECT SCOPE_IDENTITY();
In Oracle:
SELECT SEQNAME.CURRVAL FROM DUAL;
In PostgreSQL:
SELECT lastval();
(edited: lastval is any, currval requires a named sequence)
Note: lastval() returns the latest sequence value assigned by your session, independently of what is happening in other sessions.
In SQL Server, you can do (in addition to the other solutions already present):
INSERT INTO dbo.Users(Name, Age)
OUTPUT INSERTED.ID AS 'New User ID'
VALUES('charuka', 12)
The OUTPUT clause is very handy when doing inserts, updates, deletes, and you can return any of the columns - not just the auto-incremented ID column.
Read more about the OUTPUT clause in the SQL Server Books Online.
In Oracle and PostgreSQL you can do this:
INSERT INTO some_table (name, age)
VALUES
('charuka', 12)
RETURNING ID
When doing this through JDBC you can also do that in a cross-DBMS manner (without the need for RETURNING) by calling getGeneratedKeys() after running the INSERT
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. I was looking for something like this for ages, with this detailed break down, I hope this helps.