How can i update a table using this view - sql

I have 3 tables called Airlines,Destinations and PriceTable.
The Airlines table has two columns - Airline_ICAO_Code and Airline. The Destinations table has two columns - Airport_ICAO_Code and Destination. The PriceTable has these columns - ID,Airport_ICAO_Code, Airline_ICAO_Code,Departure,Price and RouteStaus.
The PK in PriceTable is ID.The PK in Airlines table is Airline_ICAO_Code. The PK in Destinations table is Airport_ICAO_Code. The columns Airport_ICAO_Code and Airline_ICAO_Code in the price table are FKs.
I created a view called InputFlightPrices which i want to use to update the PriceTable which stores the flight prices. The reason im using the view to do this is that it allows me to see clearly what airline routes need updating as its difficult to determine the airline and destination from the codes.
This is the view code:
Create View InputFlightPrices
As
Select ID,Airline,Destination,AirportName,Price,Departure,RouteStatus
From Airlines As a
Join PriceTable As p
On a.Airline_ICAO_Code = p.Airline_ICAO_Code
Join Destinations As d
On d.Airport_ICAO_Code = p.Airport_ICAO_Code;
I want the view to display all airlines a-z but I cannot use an Order By clause in the view.
I therefore ran the query below on the view to order the airlines in the view A-Z
Select * from InputFlightPrices
Order By Airline Asc
The resulting view from the above statement displays correctly but it does not allow me to edit the records in it in order to update the table.
Is there a solution.
Thanks for any help offered.
Im editing this in response to Philpxy to try and clarify what i want:
I want to update a table called PriceTable which contains flight prices.
The Airline and Destination columns within the PriceTable contain codes. It is difficult to know what airline and destination to update from these codes so I created a view called InputFlightPrices which shows the Airline and Destination names. This makes it easy to enter the prices for the correct routes.
The problem with the View is that the Airline column is not sorted. Records belonging to an Airline are scattered throughout the table. This could lead to me missing some routes that need to be updated.
Therefore I created a select statement which Ordered the View by Airline A-Z.
The problem that i have now is that I cannot update the PriceTable using this View(the result of select statement) as It does not allow me to edit it.I tried to edit by clicking it directly using the GUI.
I hope thats clear.

As you have multiple joins in view, the update may not update the records correctly. You can use triggers here to update the table.

You may be able to edit your Select * from InputFlightPrices Order By Airline Asc query per answers to How to quickly edit values in table in SQL Server Management Studio?:
In Mgmt Studio, when you are editing the top 200, you can view the SQL
pane - either by right clicking in the grid and choosing Pane->SQL or
by the button in the upper left. This will allow you to write a custom
query to drill down to the row(s) you want to edit.
Go to Tools > Options. In the tree on the left, select SQL Server
Object Explorer. Set the option "Value for Edit Top Rows command" to
0. It'll now allow you to view and edit the entire table from the context menu.
Re updating when the query result involves a view:
From SQL Server 2014 CREATE VIEW (Transact-SQL)
The SELECT clauses in a view definition cannot include the following:
An ORDER BY clause, unless there is also a TOP clause in the select list of the SELECT statement
The ORDER BY clause is used only to determine the rows that are returned by the TOP or OFFSET clause in the view definition. The ORDER
BY clause does not guarantee ordered results when the view is queried,
unless ORDER BY is also specified in the query itself.
[...]
You can modify the data of an underlying base table through a view, as
long as the following conditions are true:
Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table.
[...]
Generally, the
Database Engine must be able to unambiguously trace modifications from
the view definition to one base table.
Per the last sentence: If you want to update a base table for a particular row then it has to be just one base table's columns, columns of some key from that base table must be in the view (UNIQUE NOT NULL or PRIMARY KEY), and you must not be updating those columns.
Otherwise when you ask to update some row in the view it's not clear what row in what base table is to be updated.
See also SQL Server 2014 Modify Data Through a View.

Related

Update JOIN table contents

I have a table joined from two other tables. I would like this table to stay updated with entries in the other two tables.
First Table is "employees"
I am using the ID, Last_Name, and First_Name.
And the second Table is "EmployeeTimeCardActions"
using columns ID, ActionTime, ActionDate, ShiftStart, and ActionType.
ID is my common column that the join was created by..Joined Table...
Because I usually have a comment saying I did not include enough information, I do not need a exact specific code sample and I think I have included everything needed. If there is a good reason to include more I will, I just try to keep as little company information public as possible
Sounds like you're having your data duplicated across tables. Not a smart idea at all. You can update data in one table when a row is updated in a different one via triggers but this is a TERRIBLE approach. If you want to display data joined from 2 tables, the right approach here is using an SQL VIEW which will display the current data.

Creating related table from existing parent table with automatic update

In SQL Server 2008, I need to create a child table from parent big table copying it's values in two columns and updates automatically. These values must be distinct and copy into corresponding two columns in new table. The whole idea would be making reference table with these distinct values and make relation with parent table. Thanks
Enkhzul,
You'll want to create a VIEW. A VIEW will simply run a SELECT query in the background against any tables you request in the query and display as instructed. Syntax will be:
USE [DATABASE]
GO
CREATE VIEW [VIEWNAME] AS
(
select statement here
)
After that you just need to do a SELECT query against the newly created VIEW.

Spotfire - Getting data from one table that falls between two dates in another table and adding to a calculated column

What would be the expression to create a calculated column in Table Example 2 called "SZODMAXCALC", that would contain the SZODMAXCALC from Table Example 1 given that the data from Table Example 1 falls between the dates (DTTMSTART and DTTMEND) within Table Example 2?
Maybe this is easier done on the SQL side that loads the data?
there is no way to create a calculated column that references a column in another table.
you will need to do a join either in Spotfire (via Insert...Columns)* or on the SQL-side of things (either via a view on your database or by creating a new information link in Spotfire).
the best method depends on your data structure, implementation, and desired results, so I'm not able to recommed there. take a look at both options and evaluate which one works best.
* NOTE that Spotfire cannot join based on a Calculated Column as a common key. that is, using your example, if [WELLNAME] is a calculated column, you cannot tell Spotfire the equivalent of SELECT wellname, ... FROM table_a LEFT JOIN table_b ON table_a.wellname = table_b.wellname.
the alternative is to Insert...Transformation and choose Insert New Calculated Column, and to join on that instead.
the reason for this is that calculated columns are very mutable; they could change frequently based on a user action. it would be inefficient to re-execute the join each time the column's contents changed. conversely, a "Transformation Calculated Column" is only updated when the data table is loaded.

How not to display columns which are NULL in a view

I've set up a view which combines all the data across several tables. Is there a way to write this so that only columns which contain non-null data are displayed, and those columns which contain all NULL values are not included?
ADDED:
Sorry, still studying and working on my first big project so every day seems to be a new experience at the minute. I haven't been very clear, and that's partly because I'm not sure I'm going about things the right way! The client is an academic library, and the database records details of specific collections. The view I mentioned is to display all the data held about an item, so it is bringing together tables on publication, copy, author, publisher, language and so on. A small number of items in the collection are papers, so have additional details over and above the standard bibliographic details. What I didn't want was a user to get all the empty fields relating to papers if what was returned only consisted of books, therefore the paper table fields were all null. So I thought perhaps there would be a way to not show these. Someone has commented that this is the job of the client application rather than the database itself, so I can leave this until I get to that phase of the project.
There is no way to do this in sql.
CREATE VIEW dbo.YourView
AS
SELECT (list of fields)
FROM dbo.Table1 t1
INNER JOIN dbo.Table2 t2 ON t1.ID = t2.FK_ID
WHERE t1.SomeColumn IS NOT NULL
AND t2.SomeOtherColumn IS NOT NULL
In your view definition, you can include WHERE conditions which can exclude rows that have certain columns that are NULL.
Update: you cannot really filter out columns - you define the list of columns that are part of your view in your view definition, and this list is fixed and cannot be dynamically changed......
What you might be able to do is us a ISNULL(column, '') construct to replace those NULLs with an empty string. Or then you need to handle excluding those columns in your display front end - not in the SQL view definition...
The only thing I see you could do is make sure to select only those columns from the view that you know aren't NULL:
SELECT (list of non-null fields) FROM dbo.YourView
WHERE (column1 IS NOT NULL)
and so forth - but there's no simple or magic way to select all columns that aren't NULL in one SELECT statement...
You cannot do this in a view, but you can do it fairly easily using dynamic SQL in a stored procedure.
Of course, having a schema which shifts is not necessarily good for clients who consume the data, but it can be efficient if you have very sparse data AND the consuming client understands the varying schema.
If you have to have a view, you can put a "header" row in your view which you can inspect client-side on the first row in your loop to see if you want to not bother with the column in your grid or whatever, you can do something like this:
SELECT * FROM (
-- This is the view code
SELECT 'data' as typ
,int_col
,varchar_col
FROM TABLE
UNION ALL
SELECT 'hdr' as typ
-- note that different types have to be handled differently
,CASE WHEN COUNT(int_col) = 0 THEN NULL ELSE 0 END
,CASE WHEN COUNT(varchar_col) = 0 THEN NULL ELSE '' END
FROM TABLE
) AS X
-- have to get header row first
ORDER BY typ DESC -- add other sort criteria here
If we're reading your question right, there won't be a way to do this in SQL. The output of a view must be a relation - in (over-)simplified terms, it must be rectangular. That is, each row must have the same number of columns.
If you can tell us more about your data and give us some idea of what you want to do with the output, we can perhaps offer more positive suggestions.
In general, add a WHERE clause to your query, e.g.
WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL
Here, a b c are your column names.
If you are joining tables together on potentially NULL columns, then use an INNER JOIN, and NULL values will not be included.
EDIT: I may have misunderstood - the above filters out rows, but you may be asking to filter out columns, e.g. you have several columns and you only want to display columns that contain at least one null value across all the rows you are returning. Using dynamic SQL offers a solution, since the set columns varies depending upon your data.
Here's a SQL query that builds another SQL query containing the appropriate columns. You could run this query, and then submit it's result as another query. It assumes 'pk' is some column that is always non-null, e.g. a primary key - this means we can prefix additional row names with a comma.
SELECT CONCAT("SELECT pk"
CASE (count(columnA)) WHEN 0 THEN '' ELSE ',columnA' END,
CASE (count(columnB)) WHEN 0 THEN '' ELSE ',columnB' END,
// etc..
' FROM (YourQuery) base')
FROM
(YourQuery) As base
The query works using Count(column) - the aggregate function ignores NULL values, and so returns 0 for a column consisting entirely of NULLs. The query builder assumes that YourQuery uses aliases to ensure there no duplicate column names.
While you cant put this into a view, you could wrap it up as a stored procedure that copies the data to another table - the result table. You may also set up a trigger so that the result table is updated whenever the base tables change.
I suspect what's going on is that an end user is running CrystalReports and complaining about all the empty columns that have to be removed manually.
It would actually be possible to create a stored procedure that would create a view on the fly, leaving out dataless columns. But then you would have to run this proc before using the view.
Is that acceptable?

Update all rows of a single column

I'm dealing with two tables which have 2 columns, as listed under.
Table 1: table_snapshot
account_no | balance_due
Table 2: table_ paid
account_no | post_balance | delta_balance
I added a third column to table2 with the following command:
ALTER TABLE table_paid ADD delta_balance number(18);
I'm trying to use the following query, to update the new column ( delta_balance ) with the difference in balances between 1 and 2.
FYI, table_paid is a subset of table_snapshot. i,e., table 2 has only a few accounts present in table 1. I get an error saying : SQL Statement not properly ended. the query i'm using is:
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance - table_snapshot.balance_due
from table_paid, table_snapshot
WHERE table_paid.account_no = table_snapshot.account_no;
Appreciate if someone can correct my query.
Many thanks.
novice.
Oracle doesn't have the UPDATE ... FROM syntax that you're using from MS Sql Server (which, I believe, isn't ANSI anyway). Instead, when you need to do an update on a result set, Oracle has you create the resultset as a kind of inline view, then you update through the view, like so:
UPDATE ( SELECT tp.delta_balance
, tp.post_balance
, ts.balance_due
FROM table_paid tp
JOIN table_snapshot ts
ON tp.account_no = ts.account_no
)
SET delta_balance = post_balance - balance_due;
This is more "correct" than the answers supplied by Babar and palindrom, as their queries will update every row in table_paid, even if there are no corresponding rows in table_snapshot. If there is a 1-1 correspondance, you don't need to worry, but it's safer to do it with the inline view.
It's unclear from your example which table is the parent table, or (as I'm guessing) neither is the parent table and account_no is pointing to the primary key of another table (presumably account, or "table_account" by your naming conventions). In any case, it's clear that there is not a 1-1 correspondence in your table - 15K in one, millions in the other.
This could mean 2 things: either there are many rows in table_snapshot that have no corresponding row in table_paid, or there are many rows in table_snapshot for each row in table_paid. If the latter is true, your query is impossible - you will have multiple updates for each row in table_paid, and the result will be unpredictable; how will you know which of the "post_balance - balance_due" expressions will ultimately determine the value of a given delta_balance?
If you run my query, you will find this out quickly enough - you will get an error message that says, "ORA-01779: cannot modify a column which maps to a non key-preserved table". This error will appear based not on the data in the table (it may be okay), but based on the primary keys you have defined on the two tables. If the join condition you specify doesn't unambiguously result in a 1-1 relationship between the updated table and the rest of the join, based on the defined keys, you will get this error. It's Oracle's way of telling you, "You're about to screw up your data".
In the other answers here, you will only get an error (in that case, ORA-01427: single-row subquery returns more than one row) if you actually have data that would cause a problem; my version is more strict, so it may turn out that you will need to use the other versions.
And, as the others have said, you'll definitely want an index on account_no for the table_snapshot table. One on the table_paid wouldn't hurt either.
Try this
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance -
(SELECT table_snapshot.balance_due from table_snapshot WHERE table_paid.account_no =
table_snapshot.account_no);
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance - ( select balance_due from table_snapshot
WHERE table_paid.account_no = table_snapshot.account_no )