Update a view doesn't work - sql-server

I'm working on a view which is then updated by the user. This update basically changes the value of column. But right now it doesnt let me do that and produces this :
Update or insert of view or function '' failed because it contains a derived or constant field.
I know this is because I have a constant in the select statement but is there a way to get around it? Please help
This is my code for the view
Create view Schema.View1
as
SELECT
Convert(Varchar(20),l.jtpName) as JobType, Convert(Varchar(10),' <All> ')as SubCategory , Convert(varchar (3), Case when a.jtpName= l.jtpName and a.subName= ' <All> ' then 'Yes' else 'No' end) As AutoProcess from Schema.JobType l left join Schema.Table1 a on l.jtpName=a.jtpName
UNION
SELECT
Convert(Varchar(20),a.jtpName) as JobType, Convert(Varchar(10),a.subName) as SubCategory, Convert(varchar (3),Case when b.jtpName= a.jtpName and b.subName= a.subName then 'Yes' else 'No' end) As AutoProcess from Schema.SubCategory a left join fds.Table1 b on a.subName=b.subName
GO
Finally the update statement:
UPDATE Schema.View1 SET AUTOPROCESS = Case WHEN AUTOPROCESS = 'Yes' Then 'No' END Where JOBTYPE = 'Transport' and SUBCATEGORY= 'Cargo'
Thank You

You cannot update a column that is the result of a computation.
According to MSDN, one of the conditions for a view column to be updatable is this:
Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table.
The columns being modified in the view must directly reference the underlying data in the table columns. The columns cannot be derived in any other way, such as through the following:
An aggregate function: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, and VARP.
A computation. The column cannot be computed from an expression that uses other columns. Columns that are formed by using the set operators UNION, UNION ALL, CROSSJOIN, EXCEPT, and INTERSECT amount to a computation and are also not updatable.
The columns being modified are not affected by GROUP BY, HAVING, or DISTINCT clauses.
TOP is not used anywhere in the select_statement of the view together with the WITH CHECK OPTION clause.
Here not only does your view uses the UNION statement, the AutoProcess field you are trying to update is actually the result of a CASE statement that uses two fields. It makes no sense to try and update that.
I would recommend that you use stored proc to perform writing operations. Or, as Damien suggest, you could use an INSTEAD OF trigger on the view too.

You have to create a TRIGGER and manually apply the changes from the inserted and deleted pseudo-tables against the base tables yourself.

There is no way for sql server to work backwards from your convert functions to the original fields. You cannot update a view this way.
If the view contained your jptName and subName fields, you might be able to update just those fields.

Related

Need to Add Values to Certain Items

I have a table that I need to add the same values to a whole bunch of items
(in a nut shell if the item doesn't have a UNIT of "CTN" I want to add the same values i have listed to them all)
I thought the following would work but it doesn't :(
Any idea what i am doing wrong ?
INSERT INTO ICUNIT
(UNIT,AUDTDATE,AUDTTIME,AUDTUSER,AUDTORG,CONVERSION)
VALUES ('CTN','20220509','22513927','ADMIN','AU','1')
WHERE ITEMNO In '0','etc','etc','etc'
If I understand correctly you might want to use INSERT INTO ... SELECT from original table with your condition.
INSERT INTO ICUNIT (UNIT,AUDTDATE,AUDTTIME,AUDTUSER,AUDTORG,CONVERSION)
SELECT 'CTN','20220509','22513927','ADMIN','AU','1'
FROM ICUNIT
WHERE ITEMNO In ('0','etc','etc','etc')
The query you needs starts by selecting the filtered items. So it seems something like below is your starting point
select <?> from dbo.ICUNIT as icu where icu.UNIT <> 'CTN' order by ...;
Notice the use of schema name, terminators, and table aliases - all best practices. I will guess that a given "item" can have multiple rows in this table so long as ICUNIT is unique within ITEMNO. Correct? If so, the above query won't work. So let's try slightly more complicated filtering.
select distinct icu.ITEMNO
from dbo.ICUNIT as icu
where not exists (select * from dbo.ICUNIT as ctns
where ctns.ITEMNO = icu.ITEMNO -- correlating the subquery
and ctns.UNIT = 'CTN')
order by ...;
There are other ways to do that above but that is one common way. That query will produce a resultset of all ITEMNO values in your table that do not already have a row where UNIT is "CTN". If you need to filter that for specific ITEMNO values you simply adjust the WHERE clause. If that works correctly, you can use that with your insert statement to then insert the desired rows.
insert into dbo.ICUNIT (...)
select distinct icu.ITEMNO, 'CTN', '20220509', '22513927', 'ADMIN', 'AU', '1'
from ...
;

Without updating the column values in Oracle , is there a way to store the data in a variable and get a count on those data using where condition?

I am new to Oracle. I need some help in this. So the scenario is that without updating any column value in the table I have to store a DATE value and from that DATE value I have to get a count based on a where condition, which i know we will use a '<=' operator.
For Example,lets say i have a column "Sweep_Date", in this column,for the time being all the values are nulll.
I am having nearly 2,92,300 rows in which I have to update the date values. But without updating the Sweep_Date column, Is there any way that i can store some dates in the column, for which i can write a where condition and get the count(*) from the table based upon the WHERE condition applied??
Can we use a temp Variable??
Any help is appreciated......
Aha, I think I got it.
If sweep_date is empty and you can't/won't update it, then use NVL function. For example:
select count(*)
from your_table t
where nvl(t.sweep_date, date '2020-04-28') > t.some_other_date;
If you use date column from another table, then join tables and use another table's column in NVL. For example:
select count(*)
from your_table t join another_table j on j.some_id = t.some_id
where nvl(t.sweep_date, j.some_date) > t.some_other_date;

SSRS avoid WHERE clause if select all is selected

I am working on an SSRS report and a part of my sql query is like
WHERE SuperVisorId IN (#SupervisorIDs) AND CreatedDate> #StartDate
where the #SupervisorIDs is a dropdown with option of "select all" and individual supervisors.
So if the supervisors "all" option is selected , then I don't need to include that in the where clause and my where clause is only this
WHERE CreatedDate> #StartDate
So how can I make the WHERE clause looks different according to Selection of dropdown?
This only applies if you are using a single valued parameter with a manually added All option to the list of available values. Multi-value parameters do not know when all options are selected.
SQL Server doesn't always execute the conditions in a where clause in the order you write them, so if you are using where (#p = 'all' or col = #p) and ... you may still be comparing your values.
If performance is a concern, you can avoid this by using a short circuiting case, that only progresses to the actual data comparison if it is necessary:
where case when #SupervisorIDs = 'All' then 1
else case when SuperVisorId = #SupervisorIDs then 1
else 0
end
end = 1
and CreatedDate > #StartDate
Assuming that you are using a dataset query to populate the supervisor parameter dropdown, then you can try this.
Create an additional hidden parameter of a boolean type. For this example, I'll call it #AllSupsSelected. Set the default value of the parameter to:
=COUNT(Parameters!SupervisorIds.Label)=COUNT(Fields!SupervisorIdLabel.Value,"SupervisorDataset")
Replace the field and dataset names accordingly. If the dataset is returning non-distinct values, you may have to tinker further to get this working.
Now your query can read:
WHERE #AllSupsSelected OR SupervisorId IN (#SupervisorIds)
Make your where clause like below
WHERE (
(SuperVisorId IN (#SupervisorIDs))
OR (
#SupervisorIDs = 0
AND COLUMN_WITH_NULL IS NOT NULL
)
)
AND CreatedDate > #StartDate
And pass 0 when selected "select all"
As an actual answer to your particular problem, set your multi-valued parameter dataset up similar to this to return all Supervisors as well as a value at the bottom of the list for No Supervisor:
select distinct SupervisorID as Value
,SupervisorName as Label
,1 as Sort
from Suppliers
union all
select <Uniquely identifiable value with the same data type as SupervisorID> as Value
,'No Supervisor' as Label
,2 as Sort
order by Sort
,Label
Then in your dataset set up your filtering similar to the below. I have structured it in this manner to avoid using the isnull function on your SupervisorID column, which will hurt the query performance:
select cols
from tables
where SupervisorID in(#SupervisorID)
or (SupervisorID is null
and <Unique value from above> in (#SupervisorID)
)
which version of ssrs ? in 2016, you don't need to alter your query. when you click "select all" by default it pass all the values. so your query works good without changing anything.
thanks,
SK

Change order of columns appearing in results, without changing select order

I have a query where I'm selecting more than 15 things, and thus getting (more than) 15 columns in my results. Some of the things I've selected are big CASE statements. T-SQL of course displays your result in the order than you list things in the SELECT statement.
Is there a way to have the result columns displayed in a different order to help with my review of them, without
a) re-ordering how they were selected (because I'll need to do this every time I want to compare two other columns side-by-side)
i.e. Don't want to change: SELECT a,b,c,d,e,f to SELECT f,d,a,b,c,e
since a-f can each be 5-10 lines of code
b) drag-n-drop column in the results next to each other, because if I want column 2 to be next to column 9 and column 14, and all three to be at the end of the result table, then that'd a lot of dragging to do.
c) knowing the column number of what was selected as opposed to the column name
What I'm looking for is something that resembles:
Select
vi.Name
,vi.Height
,vi.Power
,case when tt.losses < 3
then 'Y'
else 'N'
end as MasteryKen
,tt.blahnum
,vi.blahtext
,vi.blahdate
,vi.blahcalc
,tt.blahflag
,vi.blahflag
,vi.blahcompare
From SenshiVitalInfo vi
Join TatakauTable tt
on vi.namecd=tt.namecd
OrderOutputResults by tt.blahflag, vi.blahflag, *
Does a function to do the last line exist in T-SQL (SQL Server 2008)?
There is no functionality in TSQL to "move" the columns around, other than editing the SELECT list order, this is the best you can do:
SELECT
d.Name
,d.Height
,d.Power
,d.MasteryKen --<<can now move around single lines
,d.blahnum
,d.blahtext
,d.blahdate
,d.blahcalc
,d.blahflag
,d.blahflag
,d.blahcompare
FROM (Select
vi.Name
,vi.Height
,vi.Power
,case when tt.losses < 3
then 'Y'
else 'N'
end as MasteryKen
,tt.blahnum
,vi.blahtext
,vi.blahdate
,vi.blahcalc
,tt.blahflag
,vi.blahflag
,vi.blahcompare
From SenshiVitalInfo vi
Join TatakauTable tt
on vi.namecd=tt.namecd
) d
--ORDER BY ....
You can wrap your existing query inside a derived table, where you can then move the single line columns names all you want. Just make sure that any ORDER BY is moved out of the derived table.
If You are using SSMS, you can view your result set in "results to grid" mode and just drag and drop the column headings to slide the columns around.
No this does not exist.
If you don't like moving the case statements you could put the query into a view that you select from and then you select list will be simplified, but that seems like a waste of effort to me.
I don't think this functionality is part of any SQL variant.
If you are using a SQL IDE to view the result set you might be able to drag the columns you want together, I used to do this in SSMS.
Otherwise Abe's answer is all you can do.

SQL Server Reference a Calculated Column

I have a select statement with calculated columns and I would like to use the value of one calculated column in another. Is this possible? Here is a contrived example to show what I am trying to do.
SELECT [calcval1] = CASE Statement, [calcval2] = [calcval1] * .25
No.
All the results of a single row from a select are atomic. That is, you can view them all as if they occur in parallel and cannot depend on each other.
If you're referring to computed columns, then you need to update the formula's input for the result to change during a select.
Think of computed columns as macros or mini-views which inject a little calculation whenever you call them.
For example, these columns will be identical, always:
-- assume that 'Calc' is a computed column equal to Salaray*.25
SELECT Calc, Salary*.25 Calc2 FROM YourTable
Also keep in mind that the persisted option doesn't change any of this. It keeps the value around which is nice for indexing, but the atomicity doesn't change.
Unfortunately not really, but a workaround that is sometimes worth it is
SELECT [calcval1], [calcval1] * .25 AS [calcval2]
FROM (SELECT [calcval1] = CASE Statement FROM whatever WHERE whatever)
Yes it's possible.
Use the WITH Statement for nested selects:
Two ways I can think of to do that. First understand that the calval1 column does not exist as far as SQL Server is concerned until the statement has run, therefore it cannot be directly used as showning your example. So you can put the calculation in there twice, once for calval1 and once as substitution for calcval1 in the calval2 calculation.
The other way is to make a derived table with calval1 in it and then calculate calval2 outside the derived table something like:
select calcval1*.25 as calval2, calval1, field1, field2
from (select casestament as cavlval1, field1, field2 from my table) a
You'll need to test both for performance.
You should use an outer apply instead of a subselect:
select V.calc,V.calc*0.25 from FOO outer apply (select case Statement as calc) V
You can't "reset" the value of a calculated column in a Select clause, if that's what you're trying to do... The value of a calculated column is based on the calculated column formulae. Which CAN include the value of another calculated column.... but you canlt reset the formulae in a Select clause... if all you want to do is "output" the value based on two calculated columns, (as the syntax in your question reads" Then the
"[calcval2]"
in
SELECT [calcval1] = CASE Statement, [calcval2] = [calcval1] * .25
would just become a column alias in the output of the Select Clause.
or are you asking how to define the formulae for one calculated column to be based on another?

Resources