SQL - keep values with UPDATE statement - sql

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;

Related

Get back the id of each insert in SQL Server

Let's say we want to insert two users and I want to know the userId of each record I inserted.
Example:
Db:
User.lookup database with these columns:
UserId(PK, identity) | Username
Setup, insert two users:
declare #users table (uniqueId INT, name nvarchar(100));
insert into #users (0, 'TestUser')--Two users with the same name, they'll get a different userid in the db
insert into #users (1, 'TestUser')--Uniqueid is just an autonumber I use to tell the difference between them.
Insert statement:
insert into user.lookup (userName)
output inserted.userid
select name from #users;
This will return two usersIds, example 1 & 2. But how do I know which of the two users got which userId?
I can differentiate them in code with their 'uniqueid' I pass but I don't know how to return it.
Don't just output the id. You can include other columns:
insert into user.lookup (userName)
output inserted.*
select name from #users;
Here is a db<>fiddle.
You can't correlate the inserted rows with the database-assigned IDs, at least not without inserting an alternate key as well. INSERT ... OUTPUT will not let you output a row that wasn't actually inserted, so the column that correlates the un-keyed rows with the new key values has to be actually inserted.
So the options are:
To use a SEQUENCE instead of IDENTITY and and either assign IDs to the table variable before insert, or assign IDs to the entities on the client, eg by calling sp_sequence_get_range.
Use MERGE instead of INSERT. This is what Entity Framework Core does. See eg The Case of Entity Framework Core’s Odd SQL
As Gordon explained, one can output more than 1 column.
But just to put my 2 cents in, such insert doesn't really need an intermediate table variable.
create table lookup (
lookupId int identity primary key,
userName nvarchar(100),
createdOn datetime2 not null
default sysdatetime()
)
GO
✓
insert into lookup (userName) values
('TestUser1')
,('TestUser2')
;
GO
2 rows affected
insert into lookup (userName)
output inserted.lookupId, inserted.userName
values
('Testuser3'),
('Testuser3')
GO
lookupId | userName
-------: | :--------
3 | Testuser3
4 | Testuser3
select lookupId, userName
--, convert(varchar,createdOn) as createdOn
from lookup
order by lookupId
GO
lookupId | userName
-------: | :--------
1 | TestUser1
2 | TestUser2
3 | Testuser3
4 | Testuser3
db<>fiddle here

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 :-

How can I update the table in SQL?

I've created a table called Youtuber, the code is below:
create table Channel (
codChannel int primary key,
name varchar(50) not null,
age float not null,
subscribers int not null,
views int not null
)
In this table, there are 2 channels:
|codChannel | name | age | subscribers | views |
| 1 | PewDiePie | 28 | 58506205 | 16654168214 |
| 2 | Grandtour Games | 15 | 429 | 29463 |
So, I want to edit the age of "Grandtour Games" to "18". How can I do that with update?
Is my code right?
update age from Grandtour Games where age='18'
No, in update, you'll have to follow this sequence:
update tableName set columnWanted = 'newValue' where columnName = 'elementName'
In your code, put this:
update Channel set age=18 where name='Grandtour Games'
Comments below:
/* Channel is the name of the table you'll update
set is to assign a new value to the age, in your case
where name='Grandtour Games' is referencing that the name of the Channel you want to update, is Grandtour Games */
alter table changes the the schema (adding, updating, or removing columns or keys, that kind of thing).
Update table changes the data in the table without changing the schema.
So the two are really quite different.
Here is your answer -
-> ALTER is a DDL (Data Definition Language) statement
UPDATE is a DML (Data Manipulation Language) statement.
->ALTER is used to update the structure of the table (add/remove field/index etc).
Whereas UPDATE is used to update data.
Hope this helps!

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

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

how to re-insert all of the existing fields but only change one field data in postgresql?

I have bunch of data in one table, for example lets say I have a table with four columns.
id,name,age,address.
id stays the same but all the other fields changes. i.e it will look something like this.
id name age address
1 steve 20 test address 1
1 mark 21 test address 2
and now I want to have the same data set but only change the id, for example everything will stay the same but only the id changes to look something like this:
id name age address
1 steve 20 test address 1
1 mark 21 test address 2
2 steve 20 test address 1
2 mark 21 test address 2
but I don't want to insert it one field at a time, because I have 100's of fields and to do it like that will waste so much time.
so my question is how can i do this as easily as possible in Postgres?
I forgot to mention the other fields are not set by default and I want to copy the data from a specific field id, so in general it should be like. first I want to grab all the fields from a specific id, then insert these fields again but now with the new id which is 2 for example.
insert into table(id,name,age,address) select 2,name,age,address from table
create table list (id int,name text,age int,address text);
insert into list values (1,'steve',20,'AAAAAAAAA');
insert into list values (1,'mark',21,'BBBBBBBBB');
Now create a function for the INSERT Operation:
create or replace function ins_list(_updateID int ,_getID int) returns void as
$$
-- _updateID : - the new ID that you want to insert(ex. 2)
-- _getID : - the ID that you need to search to get values from name,age,address (ex.1)
insert into list (id,name,age,address) select _updateID,name,age,address from list where id = _getID
$$
language sql
to Insert you just need to call like
select ins_list(2,1);