I'm creating a view that references 3 tables. The view is from the dbo.LoadedFiles table, where I manually insert filenames and filetypes.
The other two are dbo.LandingPages and dbo.ExitPages. Both of those have a FOREIGN KEY reference column from dbo.LoadedFiles ID called LoadedFile_id.
I want the view to show which LoadedFile has not yet been imported into my dbo.LandingPages and dbo.ExitPages tables.
Here is my code thus far, I know it's wrong, but just so you guys have reference.
CREATE VIEW [dbo].[vw_FilesNotYetLoaded]
AS
SELECT
lf.ID,
filename,
filetype
FROM JPStarter.dbo.LoadedFiles lf
JOIN JPStarter.staging.ExitPages AS ep ON lf.ID = ep.LoadedFile_id
JOIN JPStarter.staging.LandingPages AS lp ON lf.ID = lp.LoadedFile_id
WHERE lf.ID NOT IN (
SELECT ID
FROM JPStarter.dbo.LoadedFiles
)
You don't need to join to the tables at all to give the desired result. Notice the UNION operator in the subquery.
CREATE VIEW [dbo].[vw_FilesNotYetLoaded]
AS
SELECT
[ID]
,[filename]
,[filetype]
FROM
[JPStarter].[dbo].[LoadedFiles]
WHERE
[ID] NOT IN (
SELECT
[LoadedFile_id]
FROM
[JPStarter].[staging].[ExitPages]
UNION
SELECT
[LoadedFile_id]
FROM
[JPStarter].[staging].[LandingPages]
);
Related
I create a table by linking two different tables in PostgreSQL. I do this with a sentence like this:
CREATE TABLE t_aux_prop_delay
AS
SELECT r.cell, r.kpi_name, r.the_geom, d.max as pd_end_point, round(k.avg_samples, 2) AS avg_samples
from t_cell_regions r, kpi_definition d,
(
SELECT cell, kpi_name, avg(kpi_value) AS avg_samples
from t_prop_delay_values
GROUP BY cell, kpi_name
) k
WHERE r.kpi_name = d.kpi_name
AND r.cell = k.cell
AND r.kpi_name = k.kpi_name
ORDER BY r.cell, d.max;
I want to know if it is possible to propagate the indexes from one of those tables to the new table so I do not have to create them all over again.
Maybe this select can help you:
SELECT REPLACE(indexdef, indexname, indexname||1)
FROM pg_indexes
WHERE TABLENAME = 'YOUR_TABLE_NAME';
It will give you a "CREATE INDEX" code with a different name (that is why I have added/concatenated 1 at the end). You are creating a new object so it has to have a different name...
And here is another code where you can also get the "CREATE INDEX" code with the different table name.
SELECT REPLACE(REPLACE(indexdef, indexname, indexname||1), tablename, 'your_tablename')
FROM pg_indexes
WHERE TABLENAME = 'personeel_medspec';
I am trying to standardise a view which is different between two customers. One of the differences is a LEFT JOIN to a table in a database which exists for only one of the customers, as it is only relevant to them. I don't want to have to create the database on the other customers server. I also want to avoid creating as another view as there are a lot of dependencies attached.
I have tried adding a SYNONYM but as the database and table doesn't exist on the other server, this causes an error.
I have tried to add logic into a view but a bit limited here.
CREATE TABLE #Product
(
ProductID INT IDENTITY(1,1) NOT NULL,
Product_Name VARCHAR(100) NOT NULL
)
INSERT #Product
(
Product_Name
)
SELECT 'Example Product 1' UNION
SELECT 'Example Product 2'
CREATE TABLE #CustomerDB_Product -- This is a replica of the table which exists in the customer specific database
(
CustomerDBProductID INT IDENTITY(1,1) NOT NULL,
CustomerDBProduct_Name VARCHAR(100) NOT NULL
)
INSERT #CustomerDB_Product
(
CustomerDBProduct_Name
)
SELECT 'Example Customer Product 1'
SELECT P.ProductID,
MAX(P.Product_Name) AS Product_Name,
MAX(CASE WHEN CP.CustomerDBProductID IS NOT NULL THEN CP.CustomerDBProduct_Name ELSE P.Product_Name END) AS CustomerProduct_Format
FROM #Product P
LEFT JOIN #CustomerDB_Product CP ON CP.CustomerDBProductID = P.ProductID
GROUP BY
P.ProductID
-- DROP TABLE #Product
-- DROP TABLE #CustomerDB_Product
Where the customer specific database exists I would expect to see the CustomerProduct_Format column picking up data and where the customer specific database doesn't exist I would expect the CustomerProduct_Format column to be an exact match to the Product_Name column.
The proposed solution needs to be able to be written as a view.
What I meant by adding a synonym. For Customer A, you have a view that includes the tables or column that only exists for Customer A.
CREATE VIEW dbo.ViewForCustomerA
AS
SELECT ... FROM <tables that exist for everyone>
JOIN <table that only exists for CustomerA>;
GO
For everyone else (and even Customer A), you have a different view that doesn't include those objects:
CREATE VIEW dbo.ViewForEveryoneElse
AS
SELECT ... FROM <tables that exist for everyone>;
GO
Then, only in customer A's database, create a synonym that points to their special view:
CREATE SYNONYM dbo.ViewName FOR dbo.ViewForCustomerA;
And for everyone else, you create the same synonym, but point it at the view for everyone:
CREATE SYNONYM dbo.ViewName FOR dbo.ViewForEveryoneElse;
Now, all the rest of your code that references the underlying view, can instead reference dbo.ViewName - it will work regardless of which customer it is, saving a whole lot of hassle making all of your queries conditional or maintaining a messy slew of nested views.
We have a self-referenced table like this
CREATE TABLE Categories(
Id int IDENTITY(1,1) NOT NULL,
Title nvarchar(200) NOT NULL,
ParentId int NULL,
CONSTRAINT PK_Structures PRIMARY KEY CLUSTERED
(
Id ASC
)
CREATE NONCLUSTERED INDEX IX_Structures_ParentId ON Categories
(
ParentId ASC
)
And a recursive cte to get all ancestors:
Create View Ancestors
as
with A(Id, ParentId) as
(
select Id, Id from Categories
union all
select e.Id, p.ParentId from Categories e
join A p on e.ParentId = p.Id
)
select * from A
Now we query all ancestors of a given Category like:
select * from Ancestors where Id = 1234
It takes 11 seconds for a table just containing 100000 categories, and the execution plan is. The query returns 5 rows for the given Id
I know I can greatly improve the performance by using hierarchyid, also I know that sometimes using while can be more performant, but in a simple case like this, I expect to see a much better performance.
Also, please note that I already have an index on ParentId
(The picture shows the table structure which is the actual name of Category table mentioned in the question.
Is there a tuning to greatly improve this performance?
Well. It turns out the reason for the slowness, and the fix are far more interesting than anticipated.
Sql server optimizes the queries based on their definition and not by what semantic meaning they might have. The view in question starts with all Categories and adds new rows by finding elements from the CTE itself and their children. Now the way to find all rows in which some row has appeared as a child, you need to calculate the whole query and then filter it out. Only the human reader understands that the query calculates all the descendants of any Category, which of course also has all Ancestors of any Category. Then you know you can start from bottom and find parents recursively. This is not apparent from the query definition, only from its semantic meaning.
Rewriting the view as follows will make it fast:
Create View Ancestors
as
with A(Id, ParentId) as
(
select Id, Id from Categories
union all
select p.Id, e.ParentId from Categories e
join A p on e.Id = p.ParentId
)
select * from A
This view creates almost the same result as the view in question. The only difference is that it also shows null as an ancestor for all Categories, which makes no difference for our usage.
This view starts to build the hierarchy from bottom and goes up, which is compatible with the way we intend to query it.
How does the execution plan look like if you put the filter condition inside the CTE?
with A(Id, ParentId) as
(
select Id, Id
from Categories
WHERE Categories.ID = 1234
union all
select e.Id, p.ParentId
from Categories e
join A p on e.ParentId = p.Id
)
select *
from A;
There are my tables:
http://i.imgur.com/dzwokhh.png
I want to write a query that return all info order by categoryId and Name.
For example: I want to return from right table id = 2,15,18 (CategoryId=1)
because in the left table they belong to Java (Id=1)
This should help to solve the problem:
select *
from mytable1
join mytable2 on mytable1.ID=mytable2.CategoryID
order by mytable1.ID ,Name
I am running the query :
select
[temp_table_excel_insert_for_join].person_id,
[temp_table_excel_insert_for_join].city,
city.city_id
from
temp_table_excel_insert_for_join, city
where
temp_table_excel_insert_for_join.city = city.city
without problem now I want to have all these columns as a new table so I used
create table mytable as
( select
[temp_table_excel_insert_for_join].person_id,
[temp_table_excel_insert_for_join].city,
city.city_id
from
temp_table_excel_insert_for_join, city
where
temp_table_excel_insert_for_join.city=city.city)
but it did not work for me what should I do to make it happen? I don't want to create a view I want to have a table.but I am not familiar if I should do a left join or other things
If your goal is to create a new table mytable with the columns person_id, city, city_id then use the select ... into syntax:
select
[temp_table_excel_insert_for_join].person_id,
[temp_table_excel_insert_for_join].city,
city.city_id
into
mytable
from
temp_table_excel_insert_for_join
inner join
city on temp_table_excel_insert_for_join.city = city.city
Note that this will fail if you run it more than once as the table already would exist and you would have to drop it first.
See the documentation for more information on the into clause
Try this
select [temp_table_excel_insert_for_join].person_id
, [temp_table_excel_insert_for_join].city
,city.city_id
into mytable
from temp_table_excel_insert_for_join inner join city on temp_table_excel_insert_for_join.city=city.city)
Try separating the two operations. First:
CREATE TABLE MyTable ( etc)
Then
INSERT INTO MyTable ( <List of columns to insert> )
SELECT <Columns to insert>
FROM etc
WHERE etc
This works if you remove the brackets after your AS clause - at least in SQL Lite. So you can just write:
CREATE TABLE mytable AS
SELECT
[temp_table_excel_insert_for_join].person_id,
[temp_table_excel_insert_for_join].city,
city.city_id
FROM
temp_table_excel_insert_for_join, city
WHERE
temp_table_excel_insert_for_join.city=city.city;