Valid Query, Failed View - sql

I have had an issue with some DB2 SQL and could really use some help.
In short, people want me to create a view. I wrote a query that works and returns what we wanted... but when I wrap it with a 'CREATE VIEW' statement, the view throws errors when I query it with anything.
The query is (names changed obviously):
SELECT DISTINCT "QTable"."Add" "Q_Add", "QTable"."Approved" "Q_Approved", "QTable"."Link" "Q_Link"
FROM ((
SELECT * FROM db.schema.VTable)
"QTable" LEFT OUTER JOIN (SELECT * FROM db.schema.ETable)
"QStat" on "QTable"."Status" = "QStat"."ETable")
Each time I run this I get 10 record back. Awesome, that's what I want. When I wrap it as a View, which I do by entering:
CREATE VIEW TestSchema.TestTable AS
SELECT * FROM ( *query I just wrote above*)
It runs (very quickly) but then I run a basic SELECT * FROM viewname I always get the same error of:
SQL0206N "QTable.Status" is not valid in the context where it is used. SQLSTATE=42703
I have been stuck for a while now. I am assuming I am creating the view wrong. Any ideas? Tips?
Edit: DB2 11.1

I would get rid of just about ll the brackets and quotes. I suspect they are not necessary, unless DB2 is very non-standard sql. I've left the quotes in although I would take all of those out as well unless they are reserved words.
There is no reason to do something like from (select * from table)
The query should just be:
SELECT DISTINCT "QTable"."Add" "Q_Add", "QTable"."Approved" "Q_Approved", "QTable"."Link" "Q_Link"
FROM db.schema.VTable QTable
LEFT OUTER JOIN db.schema.ETable "QStat" on "QTable"."Status" = "QStat"."ETable"
Your view then should also not be create view as select * from (...) it should just be:
create view myView as
SELECT DISTINCT "QTable"."Add" "Q_Add", "QTable"."Approved" "Q_Approved", "QTable"."Link" "Q_Link"
FROM db.schema.VTable QTable
LEFT OUTER JOIN db.schema.ETable "QStat" on "QTable"."Status" = "QStat"."ETable"

You may have a different problem. I just tried it in DB2 10.5 and it works well:
create table vtable (
"Add" int,
"Approved" int,
"Link" varchar(20),
"Status" int
);
create table etable (
"ETable" int
);
create view my_view1 as
select
*
from
(
SELECT
DISTINCT "QTable"."Add" "Q_Add",
"QTable"."Approved" "Q_Approved",
"QTable"."Link" "Q_Link"
FROM
(
( SELECT * FROM VTable) "QTable"
LEFT OUTER JOIN
(
SELECT
*
FROM ETable
)
"QStat" on "QTable"."Status" = "QStat"."ETable"
)
)
Anyway, you have excessive parenthesis. Remove the ones you don't need.
And QTable need to be in double quotes always, as in "QTable".

Related

show columns in CTE returns an error - why?

I have a show columns query that works fine:
SHOW COLUMNS IN table
but it fails when trying to put it in a CTE, like this:
WITH columns_table AS (
SHOW COLUMNS IN table
)
SELECT * from columns_table
any ideas why and how to fix it?
Using RESULT_SCAN:
Returns the result set of a previous command (within 24 hours of when you executed the query) as if the result was a table. This is particularly useful if you want to process the output from any of the following:
SHOW or DESC[RIBE] command that you executed.
SHOW COLUMNS IN ...;
WITH columns_table AS (
SELECT *
FROM table(RESULT_SCAN(LAST_QUERY_ID()))
)
SELECT *
FROM columns_table;
CTE requires select clause and we cannot use SHOW COLUMN IN CTE's and as a alterative use INFORMATION_SCHEMA to retrieve metadata .Like below:
WITH columns_table AS (
Select * from INTL_DB.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='CURRENCIES'
)
SELECT * from columns_table;

I'm trying to create a query using the SQL SELECT statement

I'm trying to create a query using the SQL SELECT statement but I keep getting a error with my code
This is my code:
SELECT *
FROM tblRegistration
WHERE (tblRegistration.InstanceID IN (
SELECT InstanceID FROM tblRegistration
SELECT tblCourse.InstanceID, tblCourse.HoursPerWeek
FROM tblCourse
WHERE (((tblCourse.HoursPerWeek)=40));
Access throws in far more parentheses in WHERE clause than are needed. Simplify by removing most of them then test. Access will eventually throw them back in if you switch builder between datasheet and design view and save the object. Always make sure brackets, parens, quote marks, and apostrophes are evenly paired.
Also have too many SELECT clauses.
Subquery for IN() must return only one field.
Consider:
SELECT *
FROM tblRegistration
WHERE tblRegistration.InstanceID IN (
SELECT tblCourse.InstanceID
FROM tblCourse
WHERE tblCourse.HoursPerWeek=40);
If you don't want to remove field from subquery, try:
SELECT *
FROM tblRegistration
WHERE EXISTS (
SELECT tblCourse.InstanceID, tblCourse.HoursPerWeek
FROM tblCourse
WHERE tblCourse.HoursPerWeek=40);

"Object not found" error when using multiple table expressions in WITH...AS inside of CREATE VIEW

I am trying to create a view based on complex query in HSQLDB (version 2.5.1).
The query looks like this (simplified for clarity), also includes DDL for the tables:
DROP VIEW TEST_VIEW IF EXISTS;
DROP TABLE TEST_1 IF EXISTS;
CREATE TABLE TEST_1 (
contentid VARCHAR(10),
contenttype VARCHAR(10),
downloaddate TIMESTAMP
);
DROP TABLE TEST_2 IF EXISTS;
CREATE TABLE TEST_2 (
dbid INTEGER,
contentid VARCHAR(10),
version VARCHAR(10)
);
CREATE VIEW TEST_VIEW AS
WITH a AS (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
),
b AS (
SELECT CONTENTID, amount
FROM a
)
SELECT b.CONTENTID, b.amount, i.DOWNLOADDATE
FROM b /* error here */
JOIN TEST_1 i ON i.CONTENTID = b.CONTENTID
ORDER BY b.CONTENTID;
However, it fails with the following error:
[42501][-5501] user lacks privilege or object not found: JOIN in statement [CREATE VIEW TEST_VIEW AS......
The same query runs fine when used as a SELECT (without CREATE VIEW...AS).
Also, the view is created successfully if there is only one table expression in WITH...AS statement, like below:
CREATE VIEW TEST_VIEW AS
WITH a AS (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
)
SELECT a.CONTENTID, a.amount, i.DOWNLOADDATE
FROM a
JOIN TEST_1 i ON i.CONTENTID = a.CONTENTID
ORDER BY a.CONTENTID;
It looks like in the first statement the DB engine tries to parse "JOIN" as a table alias for table "b".
Is there a syntax error I have not noticed, or does HSQLDB not support multiple table expressions in WITH...AS inside of CREATE VIEW?
Edit: Updated example query to include table DDL for completeness.
HSQLDB supports creating this type of view.
As you haven't provided table definitions, I tried with a similar query with the test tables that are generated by DatabaseManager and it was successful. Please report the tables.
CREATE VIEW REPORT_LINKED_IDS AS
WITH a AS (
SELECT PRODUCTID, count(*) AS amount
FROM ITEM
GROUP BY PRODUCTID
),
b AS (
SELECT PRODUCTID, amount
FROM a
)
SELECT b.PRODUCTID, b.amount, i.NAME, i.PRICE
FROM b
JOIN PRODUCT i ON i.ID = b.PRODUCTID
ORDER BY b.PRODUCTID;
Thanks to a suggestion by #fredt, I have confirmed that the issue is with trying to use this query in IntelliJ IDEA (2020.1). The query worked fine and the view was created successfully in the same DB when another tool was used (DbVisualizer in my case). Furthermore, after having created the view in DB, IntelliJ IDEA throws an exception on the same word "JOIN" when trying to connect to this DB - the error is similar to this: The specified database user/password combination is rejected: org.hsqldb.HsqlException: unexpected token: NOT. Similarly to a comment in the above question, I have recovered from the error by manually editing the .script file.
There are at least 2 possible options to resolve the issue:
1st solution: Refactor SQL query to only have one table in WITH clause. In my case I just moved the first table to a select expression in FROM clause, like below:
CREATE VIEW TEST_VIEW AS
WITH b AS (
SELECT CONTENTID, amount
FROM (
SELECT CONTENTID, count(*) AS amount
FROM TEST_2
GROUP BY CONTENTID
)
)
SELECT b.CONTENTID, b.amount, i.DOWNLOADDATE
FROM b
JOIN TEST_1 i ON i.CONTENTID = b.CONTENTID
ORDER BY b.CONTENTID;
2nd solution: Use a different tool to work with the DB, or have the issue fixed in IDEA.

performance penalty when using "join with temp table " in contrast of "IN clause with constant values"

I have a temp table with two records like this:
select * into #Tbl from (select 1 id union select 2) tbl
and also the related index:
Create nonclustered index IX_1 on #T(id)
The following query takes 4000ms to run:
SELECT AncestorId
FROM myView
WHERE AncestorId =ANY(select id from #t)
But the equivalent query (with IN and literal values) takes only 3ms to run!:
SELECT ProjectStructureId
FROM myView
WHERE AncestorId in (1,2)
Why this huge difference and how can I change the first query to be as fast as the second one?
P.S.
SQL SERVER 2014 SP2
myView is a Recursive CTE
Changing the first query to INNER JOIN model or EXISTS model didn't help
Changing the IX_1 Index to a cluster index didn't help
Using FORSEEK didn't help
P.S.2
The execution plans of both can be downloaded here : https://www.dropbox.com/s/pas1ovyamqojhba/Query-With-In.sqlplan?dl=0
Execution plans in Paste the Plan
P.S. 3
The view definition is :
ALTER VIEW [dbo].[myView]
AS
WITH parents AS (SELECT main.Id, main.NodeTypeCode, main.ParentProjectStructureId AS DirectParentId, parentInfo.Id AS AncestorId, parentInfo.ParentProjectStructureId AS AncestorParentId, CASE WHEN main.NodeTypeCode <> IsNull(parentInfo.NodeTypeCode, 0)
THEN 1 ELSE 0 END AS AncestorTypeDiffLevel
FROM dbo.ProjectStructures AS main LEFT OUTER JOIN
dbo.ProjectStructures AS parentInfo ON main.ParentProjectStructureId = parentInfo.Id
UNION ALL
SELECT m.Id, m.NodeTypeCode, m.ParentProjectStructureId, parents.AncestorId, parents.AncestorParentId,
CASE WHEN m.NodeTypeCode <> parents.NodeTypeCode THEN AncestorTypeDiffLevel + 1 ELSE AncestorTypeDiffLevel END AS AncestorTypeDiffLevel
FROM dbo.ProjectStructures AS m INNER JOIN
parents ON m.ParentProjectStructureId = parents.Id)
SELECT ISNULL(Id, - 1) AS ProjectStructureId,
ISNULL(NodeTypeCode,-1) NodeTypeCode,
DirectParentId,
ISNULL(AncestorId, - 1) AS AncestorId,
AncestorParentId,
AncestorTypeDiffLevel
FROM parents
WHERE (AncestorId IS NOT NULL)
In your good plan it is able to push the literal values right into the index seek of the anchor part of the recursive CTE.
It refuses to do that when they come from a table.
You could create a table type
CREATE TYPE IntegerSet AS TABLE
(
Integer int PRIMARY KEY WITH (IGNORE_DUP_KEY = ON)
);
And then pass that to an inline TVF written to use that in the anchor part directly.
Then just call it like
DECLARE #AncestorIds INTEGERSET;
INSERT INTO #AncestorIds
VALUES (1),
(2);
SELECT *
FROM [dbo].[myFn](#AncestorIds);
The inline TVF would be much the same as the view but with
WHERE parentInfo.Id IN (SELECT Integer FROM #AncestorIds)
in the anchor part of the recursive CTE.
CREATE FUNCTION [dbo].[myFn]
(
#AncestorIds IntegerSet READONLY
)
RETURNS TABLE
AS
RETURN
WITH parents
AS (SELECT /*omitted for clarity*/
WHERE parentInfo.Id IN (SELECT Integer FROM #AncestorIds)
UNION ALL
SELECT/* Rest omitted for clarity*/
Also you might as well change that LEFT JOIN to an INNER JOIN though the optimiser does that for you.
I just want to say that I would write the query as:
SELECT AncestorId
FROM myView
WHERE AncestorId IN (select id from #t);
I doubt this would help.
The issue is that SQL Server can optimize literal values better than values inside a table. The result is that the execution plan changes.
If neither IN nor JOIN fix the problem, then you probably have to fiddle with the definition of the view to improve performance.

Join Table to Another Table then to Itself

I'm using PowerBuilder 12.5 Connected to Oracle 9. I want to select join my employee table to an employee_position table by emp_nbr, then use that emp_nbr to join into the employee table again.
However, I do not want to use the employee_copy table as I did below, since it will be taken down soon. Here's an image that illustrates what I want to do. :
I'm not sure if I should use nested selects or if this is possible only with inner joins. So this SQL code works, and I successfully retrieve the supervisor's name:
SELECT "EMPLOYEE"."EMP_NBR",
"EMPLOYEE"."DEPT_NBR",
"EMPLOYEE"."SHOP",
"EMPLOYEE"."LAST_NAME",
"EMPLOYEE"."FIRST_NAME",
"EMPLOYEE"."MIDDLE_INITIAL",
"EMPLOYEE"."EMP_CLASS",
"EMPLOYEE_POSITION"."EMP_SUPERVISOR_ID",
"EMPLOYEE_COPY"."LAST_NAME",
"EMPLOYEE_COPY"."FIRST_NAME",
"EMPLOYEE_COPY"."MIDDLE_INITIAL"
FROM "EMPLOYEE",
"EMPLOYEE_POSITION",
"EMPLOYEE_COPY"
WHERE ( "EMPLOYEE"."EMP_NBR" = "EMPLOYEE_POSITION"."EMP_NBR" ) and
( "EMPLOYEE_POSITION"."EMP_SUPERVISOR_ID" = "EMPLOYEE_COPY"."EMP_NBR" )
So my question is: How can I do this without using the employee_copy table? Also, this has to be done in one SQL query.
No problem: A self-join will work fine:
SELECT "EMPLOYEE"."EMP_NBR",
"EMPLOYEE"."DEPT_NBR",
"EMPLOYEE"."SHOP",
"EMPLOYEE"."LAST_NAME",
"EMPLOYEE"."FIRST_NAME",
"EMPLOYEE"."MIDDLE_INITIAL",
"EMPLOYEE"."EMP_CLASS",
"EMPLOYEE_POSITION"."EMP_SUPERVISOR_ID",
"EMPLOYEE_MGR"."LAST_NAME" as mgr_last_name,
"EMPLOYEE_MGR"."FIRST_NAME" as mgr_first_name,
"EMPLOYEE_MGR"."MIDDLE_INITIAL" as mgr_last_name
FROM "EMPLOYEE",
"EMPLOYEE_POSITION",
"EMPLOYEE" EMPLOYEE_MGR
WHERE ( "EMPLOYEE"."EMP_NBR" = "EMPLOYEE_POSITION"."EMP_NBR" ) and
( "EMPLOYEE_POSITION"."EMP_SUPERVISOR_ID" = "EMPLOYEE_MGR"."EMP_NBR" )
Just use an alias for the EMPLOYEE table of EMPLOYEE_MGR.