Cassandra Update - 'Where' with timestamp clustering key - c#

I have a table in cassandra with following structure:
CREATE TABLE answers (
Id uuid,
Name text,
Description text,
LastVersion boolean,
CreationDate timestamp,
EditionDate timestamp,
PRIMARY KEY(Id, EditionDate)
)WITH CLUSTERING ORDER BY (EditionDate DESC);
The problem is when I need to update the value of the LastVersion column to false. In this case a new line is inserted only with the values ​​of the Primary Key (Id, EditionDate) + the value of the LastVersion column.
In this order:
INSERT:
insert into answers
(id, name, description, lastversion, creationdate, editiondate)
values
(uuid(), 'Test 1', 'Description 1', true, dateof(now()), dateof(now()));
RESULT:
id | editiondate | creationdate | description | lastversion | name
--------------------------------------+---------------------------------+---------------------------------+---------------+-------------+--------
ac4f9ec1-8737-427c-8a63-7bdb62c93932 | 2018-08-01 19:54:51.603000+0000 | 2018-08-01 19:54:51.603000+0000 | Description 1 | True | Test 1
UPDATE:
update answers
set lastversion = false
where id = ac4f9ec1-8737-427c-8a63-7bdb62c93932
and editiondate = '2018-08-01 19:54:51';
RESULT:
id | editiondate | creationdate | description | lastversion | name
--------------------------------------+---------------------------------+---------------------------------+---------------+-------------+--------
ac4f9ec1-8737-427c-8a63-7bdb62c93932 | 2018-08-01 19:54:51.603000+0000 | 2018-08-01 19:54:51.603000+0000 | Description 1 | True | Test 1
ac4f9ec1-8737-427c-8a63-7bdb62c93932 | 2018-08-01 19:54:51.000000+0000 | null | null | False | null
What is wrong? Actually the EditionTime field seems to be different but, I spend the same value on UPDATE query.

your update is using a different value for editionDate than you inserted so your update is not finding the original row. And Cassandra updates and inserts are really upserts so a new row with the new key is being inserted.
Notice the EditionDate has millisecond precision but your update is only specifying it to the nearest second.

Related

how can i check if value exists before the date specified in sql server

I have the data below in a sql table,
ID | supplier | Supplier_Due | Date |
1 | S-0003 | 14850 |2020-11-09
2 | S-0003 | 850 |2020-11-09
3 | S-0003 | 21750 |2020-11-13
4 | S-0003 | 975 |2020-11-15
5 | S-0003 | 75 |2020-11-17
let assume the user wants to get data of 2020-11-13 which is
3 | S-0003 | 21750 |2020-11-13
but i'd like to get the previous supplier due as well before the date specified which is
850
along with
3 | S-0003 | 21750 |2020-11-13
so the actual query i wanna get is this
ID | supplier | Supplier_Due | Date | Previous Due
3 | S-0003 | 21750 |2020-11-13 | 850
and if there is no previous due i wanna return
ID | supplier | Supplier_Due | Date | Previous Due
3 | S-0003 | 21750 |2020-11-13 | 0.00
i couldn't even figure out how to write the query because i dont understand how to go about it
You can use window functions. Assuming that date can be used to consistently order the records of each supplier:
select *
from (
select t.*,
lag(supplier_due, 1, 0) over(partition by supplier order by date) as previous_due
from mytable t
) t
where date = '2020-11-13' and supplier = 'S-0003'
A typical alternative is a subquery, or a lateral join:
select t.*, coalesce(t1.supplier_due, 0) as previous_due
from mytable t
outer apply (
select top (1) supplier_due
from mytable t1
where t1.supplier = t.supplier and t1.date < t.date
order by t1.date desc
) t1
where date = '2020-11-13' and supplier = 'S-0003'
DECLARE #Suppliers table
(
ID integer PRIMARY KEY CLUSTERED,
Supplier char(6) NOT NULL,
Supplier_Due smallmoney NOT NULL,
[Date] date NOT NULL
);
INSERT #Suppliers
(ID, Supplier, Supplier_Due, [Date])
VALUES
(1, 'S-0003', 14850, '2020-11-09'),
(2, 'S-0003', 850, '2020-11-09'),
(3, 'S-0003', 21750, '2020-11-13'),
(4, 'S-0003', 975, '2020-11-15'),
(5, 'S-0003', 75, '2020-11-17');
SELECT
S.ID,
S.Supplier,
S.Supplier_Due,
S.[Date],
[Previous Due] =
LAG(S.Supplier_Due, 1, 0) OVER (
PARTITION BY S.Supplier
ORDER BY S.[Date] ASC)
FROM #Suppliers AS S
WHERE
S.[Date] = CONVERT(date, '2020-11-13', 121);
db<>fiddle demo
Documentation: LAG (Transact-SQL)

Check child records of a record before making status of it as false in SQL Server

I have a application with some relational tables in my SQL Server database.
In the application, whenever user deletes and records I never delete it from my database, instead I make 'status' (table column) as 'False'.
Eg: User will delete a record from tblAccounts, the records has a column 'Status' which can be either true/false. On delete action record is set to false.
Now the problem is this account may be referred in other transactions. If it is used in other tables then it should not allow user to delete (make it false).
If I allow user to delete the record physically from table, it will throw foreign key error but in this scenario (making it false) how can I check the child rows without deleting and prompt the User.
I can do it by a select query on each table but that will be slow down my application.
Is there any other way/idea to achieve it?
I can do it by a select query on each table but that will be slow down
my application.
Is there any other way/idea to achieve it?
No there is not. You can do the automation with either a CHECK constraint that calls a function or with a TRIGGER, but in that code a SELECT statement against the other tables will have to be performed. There is no way around it.
You could do it using a foreign key, the trick here is to make both columns (AccountID and Status) Primary in tblAccounts. Then in the transaction table, you create a foreign key to both (AccountID and Status) with cascade on UPDATE/Delete. This means, if you ever change/delete an account id or its status from tblAccounts, the changes will be applied on all foreign keys as well.
Here is an example :
CREATE TABLE tblAccounts(
ID INT,
AccountID INT NOT NULL,
[Status] BIT NOT NULL
)
ALTER TABLE tblAccounts
ADD PRIMARY KEY (AccountID, [Status])
CREATE TABLE tblTransactions(
[ID] INT,
[TransID] INT NOT NULL PRIMARY KEY,
[AcctID] INT NOT NULL,
[Status] BIT NOT NULL
)
ALTER TABLE tblTransactions
ADD FOREIGN KEY (AcctID,[Status]) REFERENCES tblAccounts(AccountID, [Status])
ON UPDATE CASCADE
ON DELETE CASCADE
INSERT INTO tblAccounts (ID, AccountID, [Status])
VALUES
(1,1000,1),
(2,1100,1),
(3,1200,1),
(4,1300,1)
INSERT INTO tblTransactions(ID, TransID, AcctID,[Status])
VALUES
(1,5000,1000,1),
(2,3258,1300,1),
(3,5852,1000,1),
(4,9631,1100,1),
(5,1870,1200,1)
tblAccounts
| ID | AccountID | Status |
|----|-----------|--------|
| 1 | 1000 | true |
| 2 | 1100 | true |
| 3 | 1200 | true |
| 4 | 1300 | true |
tblTransactions
| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
| 1 | 5000 | 1000 | true |
| 2 | 3258 | 1300 | true |
| 3 | 5852 | 1000 | true |
| 4 | 9631 | 1100 | true |
| 5 | 1870 | 1200 | true |
Let's change the status of AccountID 1100 to false
UPDATE tblAccounts
SET
[Status] = 0
WHERE
AccountID = 1100
Check tblAccount
| ID | AccountID | Status |
|----|-----------|--------|
| 1 | 1000 | true |
| 2 | 1100 | false|
| 3 | 1200 | true |
| 4 | 1300 | true |
Check tblTransactions
| ID | TransID | AcctID | Status |
|----|---------|--------|--------|
| 1 | 5000 | 1000 | true |
| 2 | 3258 | 1300 | true |
| 3 | 5852 | 1000 | true |
| 4 | 9631 | 1100 | false|
| 5 | 1870 | 1200 | true |

Auto increment a column value based on another column of a database table

I am creating a university course and results management system on c# .net. I have created this table on database.
CREATE TABLE Students (
[ID] [int] IDENTITY (1, 1) NOT NULL PRIMARY KEY,
[RegistrationNo] AS ([Department] + '-' + CAST(YEAR([Date]) AS char(4)) + '-' + RIGHT('00' + CONVERT(varchar(3), ID), 3)),
[Name] [varchar](40) NOT NULL,
[Email] [varchar](50) NOT NULL,
[Department] [varchar](20) NOT NULL,
[Date] [date] NOT NULL
)
Values are:
ID | RegistrationNo | Name | Email | Department | Date
1 | CSE-2018-001 | Robiul | robiul#mail.com | CSE | 2018-05-05
2 | CSE-2018-002 | Arman | arman#mail.com | CSE | 2018-05-10
3 | EEE-2018-003 | Sayed | sayed#mail.com | EEE | 2018-06-10
4 | EEE-2017-004 | Sazzad | sazzad#mail.com | EEE | 2017-06-10
User only gives the Name,Email,Department and Date. ID and RegistrationNo is auto generateing.
But I want to increment the RegistrationNo based on Department and Year of Date. For example CSE-2017's first ID's RegistrationNo will like this 'CSE-2017-001' and the next will 'CSE-2017-002'. EEE-2018-003 will be 'EEE-2018-001'

Creating a constraint on two columns to support specific rule

I have a table storing Device details. For simplicity, the columns are:
Id (Primary Key)
Name (varchar)
StatusId (Foreign Key to Status table).
The Status table has two columns:
Id (Primary Key)
State (varchar)
and two rows:
[Id | State]
1 | Active
2 | Inactive
I would like to allow multiple devices in the Devices table with the same Name, but only one of them can have status Active at any time.
That is to say, this should be allowed in the Devices table:
[Id | Name | StatusId]
10 | Mobile001 | 1
11 | Mobile001 | 2
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 2
22 | Tablet002 | 1
23 | Tablet003 | 2
But this should not be allowed:
[Id | Name | StatusId]
10 | Mobile001 | 1 <-- wrong
11 | Mobile001 | 1 <-- wrong
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 1 <-- wrong
22 | Tablet002 | 1 <-- wrong
23 | Tablet003 | 2
Is there a way how to create a constraint in T-SQL to reject inserts and updates that violate this rule? And is there a way how to do it in EF code first using EntityTypeConfigurations and Fluent API, possibly via IndexAnnotation or IndexAttributes?
Thanks.
One method, as #ZoharPeled just commented is using a filtered unique index.
As you are only allowed one Active Device of a specific name, this can be implemented as below:
USE Sandbox;
GO
--Create sample table
CREATE TABLE Device (ID int IDENTITY(1,1),
[name] varchar(10),
[StatusID] int);
--Unique Filtered Index
CREATE UNIQUE INDEX ActiveDevice ON Device ([name], [StatusID]) WHERE StatusID = 1;
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 0); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile2', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Fails
GO
UPDATE Device
SET StatusID = 1
WHERE ID = 2; --Also fails
GO
SELECT *
FROM Device;
GO
DROP TABLE Device;
Any questions, please do ask.
In EF CF You could achieve it by setting an unique index like described in this answer.
modelBuilder.Entity<Device>()
.HasIndex(d => new { d.Name, d.StatusId })
.IsUnique();

How do a make a query to count which string appears the most in a certain column?

I'm making a program and I need to make a query to the database asking for the string that appears most often in a given column. In this example, its "stringONE".
----------------------------
| ID | Column (string) |
----------------------------
| 1 | stringONE |
----------------------------
| 2 | stringTWO |
----------------------------
| 3 | stringONE |
----------------------------
| 4 | stringONE |
----------------------------
Now I need to take the name of the string that appears the most and put it into a variable string, for example:
string most_appeared_string = sql.ExecuteScalar();
Also, what happens if there is no string that appears the most, rather 2 or more strings that appear the same amount of times, like this:
----------------------------
| ID | Column (string) |
----------------------------
| 1 | stringONE |
----------------------------
| 2 | stringTWO |
----------------------------
| 3 | stringTWO |
----------------------------
| 4 | stringONE |
----------------------------
Thanks ahead.
#KeithS
Do you have an sql-server version of the query because I'm getting some errors when trying it there. Here's a table example of what I'd like to do precisely.
------------------------------------------------
| ID | column1 (string) | author (string) |
------------------------------------------------
| 1 | string-ONE | John |
------------------------------------------------
| 2 | string-TWO | John |
------------------------------------------------
| 3 | string-ONE | Martin |
------------------------------------------------
| 4 | string-ONE | John |
------------------------------------------------
SELECT TOP (1) column1, COUNT(*) FROM table WHERE author='John' ORDER BY ID
It should return "string-ONE" since it appears the most (2) times for the author John. When trying the query in MS-SQL Management Studio though, this is the error I'm getting:
Column 'table.column1' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Nevermind the edit. Thank you.
This is a pretty easy query (in T-SQL at least):
select top 1 Column, Count(*) from Table group by Column order by Count(*) desc
ExecuteScalar, by an implementation detail, will return the string value because it's the first column of the only row in the result set, even though there are two columns. You could also use ExecuteReader to access the number of times that string occurs.
select top (1) SomeCol, count(*) as Row_Count
from YourTable
group by SomeCol
order by Row_Count desc
Also, what happens if there is no string that appears the most, rather
2 or more strings that appear the same amount of times, like this:
In that case, using the above query, you will get one arbitrary row. You can add with ties to get all rows that has the same highest value.
select top (1) with ties SomeCol, count(*) as Row_Count
from YourTable
group by SomeCol
order by Row_Count desc
SELECT max(counted) AS max_counted FROM (
SELECT count(*) AS counted FROM counter GROUP BY date
)
This could do the trick

Categories

Resources