Assign a value if the field is not null - sql

I'm working on a SQL project on MS Access.
I would like to know if there is a way to assign a same value everytime a field is NOT NULL. I know that there is the Nz() function which does the opposite, but I don't know other functions.
Also, I would like to put a different value everytime the field is NULL
My table looks like that.
date
MARCH17
JUNE18
JULY19
and I would like to get something like that.
date
1
2
PRESENT
PRESENT
5
PRESENT
If I have to create another column, it's perfectly fine too.
Thanks in advance !

You will need to place your new information in a new column, otherwise, if you run the query more than once, you will get PRESENT for everything since the first query replaces the NULL date with a sequence number.
If you have an id column you can use:
UPDATE table SET new_column = (SELECT IIF(date IS NULL, id,'PRESENT'))
If you don't have an id column (which is strongly recommended) then you'll need to generate a sequence number.

Does your table have a Primary Key? Then you want to count all nulls where primary key is less than this one to give you your number, and put present where it isn't null. So (assuming your field is F1 and Primary Key is called PK) the following calculated field
=IIf(ISNULL([F1]),DCOUNT("[PK]","MYTABLE","[PK]<" & [PK]) &""","PRESENT")

You can use:
UPDATE
YourTable
SET
[date] = IIf([date] Is Null,
(Select Count(*) + 1 From YourTable As T Where T.[date] <> 'PRESENT'),
'PRESENT'))
WHERE
[date] <> 'PRESENT'

Related

how can i replace columns specially with these rows in transact sql

how can i replace columns with those in transact sql? I only have this code this way.
I could do it directly in sms but I don't understand some things in this code so I prefer to do it directly in transact to be safer.
For example I can make an Id column with int but I don't understand the "Identity" and (1,1)... the get date I have to put it where... so here it is
Thanks
[Id] INT IDENTITY (1, 1) NOT NULL,
[DateCreated] DATETIMEOFFSET NOT NULL DEFAULT (getdate()),
These two fields (or columns) contain auto-generated data. So, let's say you have 3 fields; ID, DateCreated and Username. You will only ever enter data for Username. ID will auto-generate sequential numbers (the "(1,1)" means, "Begin with the number 1, add 1 to the previous number for each new record), and DateCreated will automatically fill with the date you add the new record.
The IDENTITY(1,1) creates an column that automatically increases based on the arguments. With the (1,1) the value of the column starts at 1 (first argument) and increases by 1 (second argument) for each new record (with a caveat or two).
For the rest of the question, what? You want to replace columns. What are you trying to replace? The DateCreated column looks fine. For both Id and DateCreated, they are tagged NOT NULL but with the IDENTITY and DEFAULT constraint, the columns will be automatically populated so you don't actually have to provide data for either column when doing an INSERT. You'll probably want to add another column that describes the thing you are inserting (i.e. Name, Description, etc.)

Informix select for update with order by

In ESQL/C I need to do a statement like this (I know that "order by" clause is not allowed in a "select ... for update")
SELECT FIRST 1 fd_foglio, fd_box_cod_soc, NVL(fd_id_subfoglio, 0)
FROM informix.foglioddt
WHERE
fd_box_data_all = TO_CHAR(CURRENT YEAR TO DAY, '%iy%m%d') AND
fd_box_cod_soc = '*'
ORDER BY fd_foglio DESC;
EXEC SQL
OPEN ifx_cursor_foglioddt_for_pending_crates;
EXEC SQL
FETCH ifx_cursor_foglioddt_for_pending_crates
INTO :fd_foglio, :fd_box_cod_soc, :local_fd_id_subfoglio;
in which I need an "order by" clause inside a "select for update" — I know that isn't allowed — in order to use a cursor successively to increment the field fd_id_subfogli (after I have used it in another part of the code) with a statement like:
UPDATE informix.foglioddt SET fd_id_subfoglio = :new_value WHERE
CURRENT OF ifx_cursor_foglioddt_for_pending_crates
How can I rewrite the previous code in order to select only the first ordered record and update a field in it?
The necessary information isn't in the question, but making a semi-educated guess, the foglioddt table has a UNIQUE constraint on columns fd_foglio and fd_id_subfoglio, but the latter can be NULL (in which case, Informix only allows one row in the table with a given fd_foglio value and a NULL fd_id_subfoglio).
Assuming that if there are any rows for a given fd_foglio value where the fd_id_subfoglio value is not null, then all the rows for that given fd_foglio value have a non-null value for the fd_id_subfoglio value, you could rephrase the UPDATE as:
UPDATE informix.foglioddt SET fd_id_subfoglio = :new_value
WHERE fd_foglio = :fd_foglio
AND (fd_id_subfoglio = :local_fd_id_subfoglio OR
fd_id_subfoglio IS NULL)
The first part of the OR condition deals with the normal case, where you've got both values that make up the primary key, and you simply change the identified row. The second part of the OR condition deals with the case where the only row in the table has fd_id_subfoglio set null.
Clearly, if my interpretation of the data structure is incorrect, then this won't work. The solution will then be to select the values from the primary key columns so that you can update using the primary key to identify the row to be updated — that's why primary keys are important! They're the way you can address individual rows by a set of values. Indexes on primary keys are also important to speed up such access (and to enforce uniqueness).

How can I update the value of a field in a table to be a random number that's unique most of the time?

I have a simple table:
CREATE TABLE [dbo].[Word] (
[WordId] INT IDENTITY (1, 1) NOT NULL,
[NameId] INT NOT NULL
PRIMARY KEY CLUSTERED ([WordId] ASC)
);
I have a unique index on NameId
I am trying to update this table and change one column to a random number:
UPDATE Word SET NameId = ROUND(RAND()*2147483647,0)
I realize there is a very very small chance this will not work but it's actually failing every time even though the table has only a very small number of rows the update always fails and says there's a duplicate.
Can anyone tell me what's happening here and also suggest a way to update this table so that there's no duplicate values of NameId created most of the time.
You are updating every NameId with same value, use WHERE statement to update only one row
EDIT: This should do the trick you are looking for, NewId() generates new id for each row
UPDATE Word SET NameId = abs(checksum(NewId()) % 2147483647)
How many rows do you have? It could be a case of the birthday paradox.
Have you tried doing this:
SELECT ROUND(RAND()*2147483647,0) FROM Word
Do the numbers really need to be pseudo-random? You could use row_number() to make them increment.

Intervals: How can I make sure there is just one row with a null value in a timstamp column in table?

I have a table with a column which contains a 'valid until' Date and I want to make sure that this can only be set to null in a single row within the table. Is there an easy way to do this?
My table looks like this (postgres):
CREATE TABLE 123.myTable(
some_id integer NOT NULL,
valid_from timestamp without time zone NOT NULL DEFAULT now(),
valid_until timestamp without time zone,
someString character varying)
some_id and valid_from is my PK. I want nobody to enter a line with a null value in column valid_until if there is already a line with null for this PK.
Thank you
In PostgreSQL, you have two basic approaches.
Use 'infinity' instead of null. Then your unique constraint works as expected. Or if you cannot do that:
CREATE UNIQUE INDEX null_valid_from ON mytable(someid) where valid_until IS NULL
I have used both approaches. I find usually the first approach is cleaner and it allows you to use range types and exclude constraints in newer versions of PostgreSQL better (to ensure no two time ranges overlap based on a given given someid), bt the second approach often is useful where the first cannot be done.
Depending on the database, you can't have null in a primary key (I don't know about all databases, but in sql server you can't). The easiest way around this I can think of is to set the date time to the minimum value, and then add a unique constraint on it, or set it to be the primary key.
I suppose another way would be to set up a trigger to check the other values in the table to see if another entry is null, and if there is one, don't allow the insert.
As Kevin said in his answer, you can set up a database trigger to stop someone from inserting more than one row where the valid until date is NULL.
The SQL statement that checks for this condition is:
SELECT COUNT(*)
FROM TABLE
WHERE valid until IS NULL;
If the count is not equal to 1, then your table has a problem.
The process that adds a row to this table has to perform the following:
Find the row where the valid until value is NULL
Update the valid until value to the current date, or some other meaningful date
Insert the new row with the valid until value set to NULL
I'm assuming you are Storing Effective-dated-records and are also using a valid from date.
If so, You could use CRUD stored procedures to enforce this compliance. E.G the insert closes off any null valid dates before inserting a new record with a null valid date.
You probably need other stored procedure validation to avoid overlapping records and to allow deleting and editing records. It may be more efficient (in terms of where clauses / faster queries) to use a date far in the future rather than using null.
I know only Oracle in sufficient detail, but the same might work in other databases:
create another column which always contains a fixed value (say '0') include this column in your unique key.
Don't use NULL but a specific very high or low value. I many cases this is actually easier to use then a NULL value
Make a function based unique key on a function converting the date including the null value to some other value (e.g. a string representation for dates and 'x' for null)
make a materialized view which gets updated on every change on your main table and put a constraint on that view.
select count(*) cnt from table where valid_until is NULL
might work as the select statement. And a check constraint limiting the cnt value to the values 0 and 1
I would suggest inserting to that table through an SP and putting your constraint in there, as triggers are quite hidden and will likely be forgotten about. If that's not an option, the following trigger will work:
CREATE TABLE dbo.TESTTRIGGER
(
YourDate Date NULL
)
CREATE TRIGGER DupNullDates
ON dbo.TESTTRIGGER
FOR INSERT, UPDATE
AS
DECLARE #nullCount int
SELECT #nullCount = (SELECT COUNT(*) FROM TESTTRIGGER WHERE YourDate IS NULL)
IF(#NullCount > 1)
BEGIN
RAISERROR('Cannot have Multiple Nulls', 16, 1)
ROLLBACK TRAN
END
GO
Well if you use MS SQL you can just add a unique Index on that column. That will allow only one NULL. I guess that if you use other RDBMS, this will still function.

Custom sort in SQL Server

I have a table where the results are sorted using an "ORDER" column, eg:
Doc_Id Doc_Value Doc_Order
1 aaa 1
12 xxx 5
2 bbb 12
3 ccc 24
My issue is to initially set up this order column as efficiently and reusably as possible.
My initial take was to set up a scalar function that could be used as a default value when a new entry is added to the table:
ALTER FUNCTION [dbo].[Documents_Initial_Order]
( )
RETURNS int
AS
BEGIN
RETURN (SELECT ISNULL(MAX(DOC_ORDER),0) + 1 FROM dbo.Documents)
When a user wants to permute 2 documents, I can then easily switch the 2 orders.
It works nicely, but I now have a second table I need to set up the same way, and I am quite sure there is a nicer way to do it. Any idea?
Based on your comment, I think you have a very workable solution. You could make it a little more userfriendly by specifying it as a default:
alter table documents
add constraint constraint_name
default (dbo.documents_initial_order()) for doc_order
As an alternative, you could create an update trigger that copies the identity field to the doc_order field after an insert:
create trigger Doc_Trigger
on Documents
for insert
as
update d
set d.doc_order = d.doc_id
from Documents d
inner join inserted i on i.doc_id = d.doc_id
Example defining doc_id as an identity column:
create table Documents (
doc_id int identity primary key,
doc_order int,
doc_value ntext
)
It sounds like you want an identity column that you can then override once it gets it initial value. One solution would be to have two columns, once call "InitialOrder", that is an auto-increment identity column, and then a second column called doc_order that initially is set to the same value as the InitialOrder field (perhaps even as part of the insert trigger or a stored procedure if you are doing inserts that way), but give the user the ability to edit that column.
It does require an extra few bytes per record, but solves your problem, and if its of any value at all, you would have both the inital document order and the user-reset order available.
Also, I am not sure if your doc_order needs to be unique or not, but if not, you can then sort return values by doc_order and InitialOrder to ensure a consistent return sequence.
If there is no need to have any control over what that DOC_ORDER value might be, try using an identity column.