I've never faced on this structure before and maybe someone knows best way to do that.
I have two tables - tab1(client_id, tab2_id) and tab2 (id, client_id, client_date) - NNN hundreds mln rows, million new rows per day.
tab1.TAB2_ID is foreign key with tab2 (tab2.ID).
I am going to create a trigger in tab2 to keep updated the latest tab2.ID in the tab1 per client_id. It means that I will change foreign key which will force to recalc the index. What do you think, is it good idea?
Or better do not make a foreign key and just keep that ID, but I need to join tab1 and tab2 in reports to reach tab2.client_date.
Thanks
I suspect this might not be your entire requirement, but aggregating data from one table into another is a good use of materialized views.
In the future please include actual DDL, DML to support a minimum reproducible example.
Let's start with tab2:
CREATE TABLE tab2 (
id NUMBER,
client_id NUMBER,
client_date DATE);
ALTER TABLE tab2
ADD CONSTRAINT tab2_pk
PRIMARY KEY (id)
USING INDEX;
Create some fake data:
INSERT INTO tab2
SELECT LEVEL,
MOD(LEVEL,
5),
trunc(SYSDATE) - MOD(LEVEL,
20)
FROM dual
CONNECT BY LEVEL < 100;
SELECT *
FROM tab2;
Yields:
1 1 12/3/2020
2 2 12/2/2020
3 3 12/1/2020
4 4 11/30/2020
5 0 11/29/2020
6 1 11/28/2020
7 2 11/27/2020
8 3 11/26/2020
9 4 11/25/2020
10 0 11/24/2020
...
Now for the materialized view. We want this view refreshed automatically when any data is changed in tab2. For this we need to create a materialized view log to track changes on the fields we are interested in.
CREATE MATERIALIZED VIEW LOG
ON tab2 WITH ROWID (id, client_id)
INCLUDING NEW VALUES;
And then the materialized view:
CREATE MATERIALIZED VIEW tab1
BUILD IMMEDIATE
REFRESH fast
ON COMMIT
AS
SELECT client_id,
MAX(id) AS tab2_id
FROM tab2
GROUP BY client_id;
Here is what tab looks like now:
SELECT *
FROM tab1;
CLIENT_ID TAB2_ID
2 97
4 99
0 95
3 98
1 96
So, here is the magic. Let's insert a new row into tab2:
INSERT INTO tab2
VALUES
(100,
4,
trunc(SYSDATE) + 100);
COMMIT;
And looking at tab1 again we see:
SELECT *
FROM tab1;
CLIENT_ID TAB2_ID
2 97
4 100 <--- changed for new CLIENT_ID 4, ID 100
0 95
3 98
1 96
All of this being said I agree with Boneist: you really might want to reconsider if you need this aggregation, second table, if you are just going to join back to the original table anyways.
Related
I have table like below,
Id(Pk) User_Id C1 C2 C3 C4
1 111 2 a b c
2 111 5 d e f
3 111 7 a f ty
4 222 2 a b c
5 222 5 d e f
6 222 7 a f ty
This table almost having 10L records. And each user_id having almost 10k Records. If I am fetching details by User_id, it is getting almost 5 mins to get the details. Where i have to tune this?
Im using below query
Select * from User where user_id ='111'
And total number of columns in this table is around 130 columns.
Assuming you have a right index defined on (User_id) & just select the column which you actually want so, i would do with backed SSMS:
SET NOCOUNT ON
SELECT User_Id, C1, C2, . . .
FROM User
WHERE user_id = 111;
If, relative index is not present with user_id then you have to pay with poor performance.
Note : If user_id has numeric type, then you don't need to use ''.
If you PK on the Id column is a clustered index, change it to non-clustered and create a clustered index on the User_Id column.
This will most likely make SQL Server use a partial table scan, and as all requested records will be saved "close to eachother", this might reduce the number of page reads required to retrieve the values (which can be "grabbed" from the disk without further criteria checks).
I am trying to build a temp table with grouped data from multiple tables (in an SP), I am successful in building the data set however I have a requirement that each grouped row have a unique id. I know there are ways to generate unique ids for each row, However the problem I have is that I need the id for a given row to be the same on each run regardless of the number of rows returned.
Example:
1st run:
ID Column A Column B
1 apple 15
2 orange 10
3 grape 11
2nd run:
ID Column A Column B
3 grape 11
The reason I want this is because i am sending this data up to SOLR and when I do a delta I need to have the ID back for the same row as its trying to re-index
Any way I can do this?
Not sure if this will help, not entirely confident of your wider picture, but ...
As your new data is assembled, log each [column a] value in a table of your own.
Give that table an IDENTITY column to do the numbering for you.
Now you can join any new data sets to your lookup table and you'll have a persistent number for each column A.
You just need to ensure that each time you query new data, you add new values to the lookup table.
create table dbo.myRef(
idx int identity(1,1)
,[A] nvarchar(100)
)
General draft as below ...
--- just simulating some input data here
with cte as (
select 'apple' as [A], 15 as [B]
UNION
select 'orange' as [A], 10 as [B]
UNION
select 'banana' as [A], 4 as [B]
)
select * into #temp from cte;
-- Put any new values into the lookup table
-- and they will be assigned a new index number by the identity column
insert into dbo.myRef([A])
select distinct [A]
from #temp where [A] not in (select [A] from dbo.myRef)
-- now pull your original data for output, joining to the lookup table to get a ref number.
select T.*,R.idx
from #temp T
inner join
oer.myRef R
on T.[A] = R.[A]
Sorry for the late reply, i was stuck with something else, however i solved my own issue.
I built 2 temp tables one with all the data from the various tables (#master) and another temp table (#final) to house all the grouped data with an empty column for ID
Next i did a concat(column1, '-',column2,'-', column3) on 3 columns from the #master and updated the #final table based on the type
this helped me to get the same concat ids on each run
I've deleted some records (more precisely row 4) from a table in a SQL Server database. Now the first column goes like this (1,2,3,5) without row 4:
ID Name
------------
1 Luk
2 Sky
3 Philips
5 Andrey
How can I recreate this table and insert all data again in appropriate order?
Like this:
ID Name
--------
1 Luk
2 Sky
3 Philips
4 Andrey
EDIT:
But if i have another column (number) that is not a key, like this:
ID Number Name
------------
1 1 Luk
2 2 Sky
3 3 Philips
5 5 Andrey
Then can i recreate column Number and Name,
ID Number Name
------------
1 1 Luk
2 2 Sky
3 3 Philips
5 4 Andrey 'Can i do this, and if can HOW?
I would make a pretty strong case for never storing this number, since it is calculated, instead you could just create a view:
CREATE VIEW dbo.YourView
AS
SELECT ID,
Number = ROW_NUMBER() OVER(ORDER BY ID),
Name
FROM dbo.YourTable;
GO
This way after you have deleted rows, your view will already be in sync without having to perform any updates.
If you need to store the value, then almost the same query applies, but just placed inside a common table expression, which is then updated:
WITH CTE AS
( SELECT ID,
Number,
NewNumber = ROW_NUMBER() OVER(ORDER BY ID)
FROM dbo.YourTable
)
UPDATE CTE
SET Number = NewNumber;
You can use dbcc command
DBCC CHECKIDENT('tableName', RESEED, 0)
It would reset identity to 0.
Note it would require to truncate table first.
You can make the ID to auto increment which by default, the starting value for AUTO_INCREMENT is 1, and it will increment by 1 for each new record.
E.g MSSQL uses IDENTITY keyword to auto increment whereas MySQL uses the AUTO_INCREMENT keyword to perform an auto-increment feature.
MSSQL
ID int IDENTITY(1,1) PRIMARY KEY
MySQL
ID int NOT NULL AUTO_INCREMENT
I have 2 MS Access Tables.
Table 1
id
room-name
Table 2
wall
cupboard
ceiling
Now... table1.room-name has the room names and table2 contains object (many) so each room name contains many objects.
My question is ... How do I set the relationships for this please?
Nothing in table 2 tells you what room things are in so you need to add a foreign key of the room to the primary key of table 1. In this case either column of table1 could be its primary key - I would use room- name and drop the id.
So table2 needs altering so that room-name is in it and the draw the connection from table1 to table2.
Something like:
[Room]
RoomId eg 1 2
RoomName eg bedroom kitchen
[RoomItem]
RoomItemId eg 1 eg 2 eg 3
RoomId eg 1 eg 1 eg 2
ItemName eg wardrobe eg bed eg cooker
Where the RoomId links the Room and RoomItem tables.
I have a couple of rows in a database table (lets call it Customer). Each row is numbered by SNo, which gets automatically incremented by the identity property inherent in MS SQLServer. But when I delete a particular row that particular row number is left blank, but I want the table to auto correct itself.
To give you a example:
I have a sample Customer Table with following rows:
SNo CustomerName Age
1 Dani 28
2 Alex 29
3 Duran 21
4 Mark 24
And suppose I delete 3rd row the table looks like this:
SNo CustomerName Age
1 Dani 28
2 Alex 29
4 Mark 24
But I want the table to look like this:
SNo CustomerName Age
1 Dani 28
2 Alex 29
3 Mark 24
How can I achieve that?
Please help me out
Thanks in anticipation
As has been pointed out doing that would break anything in a relationship with SNo, however if your doing this because you need ordinal numbers in you presentation layer for example, you can pull off a [1..n] row number with;
SELECT ROW_NUMBER() OVER(ORDER BY SNo ASC), SNo, CustomerName, Age FROM Customer
Obviously in this case the row number is just an incrementing number, its meaningless in relation to anything else.
I don't think you want to do that. Imagine the scenario where you have another table CustomerOrder that stores all customer orders. The structure for that table might look something like this:
CustomerOrder
-------------
OrderID INT
SNo INT
OrderDate DATETIME
...
In this case, the SNo field is a foreign key into the CustomerOrder table, and we use it to relate orders to a customer. If you delete a record from your Customer table (say with SNo = 1), are you going to go back and update the SNo values in the entire CustomerOrder table? It's best to just let the ID's autoincrement and not worry about spaces in the IDs due to deletions.
Why not create a view?
CREATE VIEW <ViewName>
AS
SELECT
ROW_NUMBER() OVER(ORDER BY SNo ASC) AS SNo
,CustomerName
,Age
FROM Customers
GO
Then access the data in customers table by selecting from the view.
Of course the SNo shown by the view has no meaning in the context of relationships, but the data returned will look exactly like you want it to look.
Using transactions when inserting records in the Database with C#
You have to use DBCC CHECKIDENT(table_name, RESEED, next_val_less_1);
As have been pointed out in other answers, this is a bad idea, and if the reason is for a presentation there are other solutions.
-- Add data to temp table
select SNo, CustomerName, Age
into #Customer
from Customer
-- Truncate Customer
-- Resets identity to seed value for column
truncate table Customer
-- Add rows back to Customer
insert into Customer(CustomerName, Age)
select CustomerName, Age
from #Customer
order by SNo
drop table #Customer