How to get a list of invalidated procedures and functions in a HANA database? - hana

I want to get a list of invalidated procedures and functions in a schema in HANA. Is there an easy way to do that?
Detailed problem:
I had to delete a column in a table (OWHS.Col1). All its references, joins, etc are to be replaced by another one (OLCT.Col2): E.g.
SELECT T1.Dummy FROM INV1 T1 INNER JOIN OWHS W1 ON T1.Col = W1.Col1
replaced by
SELECT T1.Dummy FROM INV1 T1 INNER JOIN OLCT L1 ON T1.Col = L1.Col2
The above example is just illustrative.
I have changed as many references as I could think of but want to verify that OWHS.Col1 is not lying anywhere in any procedure/function. Since the column is deleted now, those procedures/functions must have been invalidated. Is there a way to get a list of invalidated procedures and functions in the entire schema?
Thanks in advance.

I got the question answered on the SAP forum:
SELECT * FROM PROCEDURES WHERE IS_VALID = 'FALSE';
SELECT * FROM FUNCTIONS WHERE IS_VALID = 'FALSE';

Related

SQL join on multiple columns or on single calculated column

I'm migrating the backend a budget database from Access to SQL Server and I ran into an issue.
I have 2 tables (let's call them t1 and t2) that share many fields in common: Fund, Department, Object, Subcode, TrackingCode, Reserve, and FYEnd.
If I want to join the tables to find records where all 7 fields match, I can create an inner join using each field:
SELECT *
FROM t1
INNER JOIN t2
ON t1.Fund = t2.Fund
AND t1.Department = t2.Department
AND t1.Object = t2.Object
AND t1.Subcode = t2.Subcode
AND t1.TrackingCode = t2.TrackingCode
AND t1.Reserve = t2.Reserve
AND t1.FYEnd = t2.FYEnd;
This works, but it runs very slowly. When the backend was in Access, I was able to solve the problem by adding a calculated column to both tables. It basically, just concatenated the fields using "-" as a delimiter. The revised query is as follows:
SELECT *
FROM t1 INNER JOIN t2
ON CalculatedColumn = CalculatedColumn
This looks cleaner and runs much faster. The problem is when I moved t1 and t2 to SQL Server, the same query gives me an error message:
I'm new to SQL Server. Can anyone explain what's going on here? Is there a setting I need to change for the calculated column?
Posting this as an answer from my comment.
Usually, this is an issue with mismatched Data types between the two columns referenced. Check and make sure the data types of the two fields (CompositeID) are the same.
You have to calculate the columns before joining them as the ON clause can only access columns for the table.
It is no good to have two identical tables anyway so you should rethink your design completely.
SELECT t1a.*,t2a.*
FROM (SELECT CalculatedColumn, * FROM t1) t1a INNER JOIN (SELECT CalculatedColumn, * FROM t2 ) t2a
ON t1a.CalculatedColumn = t2a.CalculatedColumn

How to manage concurrent access in an sql procedure

I have create an sql procedure in my oracle database that I will call later on on my c# code,
the main goal of this procedure is to loop over entries and make some treatment in a condition that every entry should be treated only once.
The body of the procedure looks like that.
FOR item IN
( SELECT * FROM
(SELECT tab1.item1,tab1.item2,tab1.item3...
FROM tab1
INNER JOIN tab2 ON ...condition...
INNER JOIN TAB3 ON ...condition...
WHERE ....main_condition=true;
ORDER BY tab1.item1
)
WHERE ROWNUM < in_param
)
LOOP
.
.
.
dbms_lock.sleep(4);
.
.
.
"set main_condition=false;"
commit;
END LOOP;
What can I do in a way that when two user call this procedure at the same time, they get a different set of rows.
thank you.
"a condition that every entry should be treated only once."
That sounds like a queue. The usual way of managing that would be to implement the queue with a SELECT … FOR UPDATE SKIP LOCKED cursor. There is a very important caveat here: that the treatment you refer to in your question include something which affects the initial criteria, say by updating a status value or deleting an identifying record (or whatever - unfortunately, questions which are vague about their specifics can only attract equally vague answers).
So it might lock something like this (obviously indicative code):
cursor c_whatever is
SELECT tab1.item1,tab1.item2,tab1.item3...
FROM tab1
INNER JOIN tab2 ON ...condition...
INNER JOIN TAB3 ON ...condition...
WHERE tab1.main_condition = true
FOR UPDATE OF tab1.main_condition SKIP LOCKED ;
begin
open c_whatever;
….
update tab1
set tab1.main_condition = false
where tab1.item1 = ….
commit;
Pessimistic locking will prevent two sessions grabbing the same row. Updating the columns which feed WHERE clause will prevent the same record being treated more than once.
What can I do in a way that when two user call this procedure at the
same time, they get a different set of rows.
You can modify your query and use ORDER BY DBMS_RANDOM.VALUE to get random rows. Hence you can modify your query as
SELECT * FROM
(SELECT tab1.item1,tab1.item2,tab1.item3...
FROM tab1
INNER JOIN tab2 ON ...condition...
INNER JOIN TAB3 ON ...condition...
WHERE ....main_condition=true;
ORDER BY DBMS_RANDOM.VALUE

How do I put multiple criteria for a column in a where clause?

I have five results to retrieve from a table and I want to write a store procedure that will return all desired rows.
I can write the query like that temporarily:
Select * from Table where Id = 1 OR Id = 2 or Id = 3
I supposed I need to receive a list of Ids to split, but how do I write the WHERE clause?
So, if you're just trying to learn SQL, this is a short and good example to get to know the IN operator. The following query has the same result as your attempt.
SELECT *
FROM TABLE
WHERE ID IN (SELECT ID FROM TALBE2)
This translates into what is your attempt. And judging by your attempt, this might be the simplest version for you to understand. Although, in the future I would recommend using a JOIN.
A JOIN has the same functionality as the previous code, but will be a better alternative. If you are curious to read more about JOINs, here are a few links from the most important sources
Joins - wikipedia
and also a visual representation of how different types of JOIN work
Another way to do it. The inner join will only include rows from T1 that match up with a row from T2 via the Id field.
select T1.* from T1 inner join T2 on T1.Id = T2.Id
In practice, inner joins are usually preferable to subqueries for performance reasons.

In an EXISTS can my JOIN ON use a value from the original select

I have an order system. Users with can be attached to different orders as a type of different user. They can download documents associated with an order. Documents are only given to certain types of users on the order. I'm having trouble writing the query to check a user's permission to view a document and select the info about the document.
I have the following tables and (applicable) fields:
Docs: DocNo, FileNo
DocAccess: DocNo, UserTypeWithAccess
FileUsers: FileNo, UserType, UserNo
I have the following query:
SELECT Docs.*
FROM Docs
WHERE DocNo = 1000
AND EXISTS (
SELECT * FROM DocAccess
LEFT JOIN FileUsers
ON FileUsers.UserType = DocAccess.UserTypeWithAccess
AND FileUsers.FileNo = Docs.FileNo /* Errors here */
WHERE DocAccess.UserNo = 2000 )
The trouble is that in the Exists Select, it does not recognize Docs (at Docs.FileNo) as a valid table. If I move the second on argument to the where clause it works, but I would rather limit the initial join rather than filter them out after the fact.
I can get around this a couple ways, but this seems like it would be best. Anything I'm missing here? Or is it simply not allowed?
I think this is a limitation of your database engine. In most databases, docs would be in scope for the entire subquery -- including both the where and in clauses.
However, you do not need to worry about where you put the particular clause. SQL is a descriptive language, not a procedural language. The purpose of SQL is to describe the output. The SQL engine, parser, and compiler should be choosing the most optimal execution path. Not always true. But, move the condition to the where clause and don't worry about it.
I am not clear why do you need to join with FileUsers at all in your subquery?
What is the purpose and idea of the query (in plain English)?
In any case, if you do need to join with FileUsers then I suggest to use the inner join and move second filter to the WHERE condition. I don't think you can use it in JOIN condition in subquery - at least I've never seen it used this way before. I believe you can only correlate through WHERE clause.
You have to use aliases to get this working:
SELECT
doc.*
FROM
Docs doc
WHERE
doc.DocNo = 1000
AND EXISTS (
SELECT
*
FROM
DocAccess acc
LEFT OUTER JOIN
FileUsers usr
ON
usr.UserType = acc.UserTypeWithAccess
AND usr.FileNo = doc.FileNo
WHERE
acc.UserNo = 2000
)
This also makes it more clear which table each field belongs to (think about using the same table twice or more in the same query with different aliases).
If you would only like to limit the output to one row you can use TOP 1:
SELECT TOP 1
doc.*
FROM
Docs doc
INNER JOIN
FileUsers usr
ON
usr.FileNo = doc.FileNo
INNER JOIN
DocAccess acc
ON
acc.UserTypeWithAccess = usr.UserType
WHERE
doc.DocNo = 1000
AND acc.UserNo = 2000
Of course the second query works a bit different than the first one (both JOINS are INNER). Depeding on your data model you might even leave the TOP 1 out of that query.

JOIN works on two tables individually, but not when used together

Edit: nevermind, figured it out, answer below if you're interested.
Using Postgresql 8.4.
Here's the format of the query I need to run (names and faces have been changed to protect my paranoia. they can be provided if necessary, but this is a direct copy of my query with simple substitution for schema, table and column names):
SELECT
t1.field,
SUM(v3.quantity) as current_qty
FROM
schema1.child_table t1
JOIN (SELECT DISTINCT t1key FROM schema2.child_transaction t2 WHERE datefield BETWEEN '2012-04-01' AND '2012-04-19') t2 USING (t1key)
LEFT JOIN schema1.child_current_status v3 ON t1.t1key = v3.t1key
JOIN schema1.parent_table t4 ON t1.t4key = t4.t4key
WHERE
t4.criteria = 763
GROUP BY
t1.field
... basically, I need the field from child_table when criteria matches my provided data in parent_table, and when there is at least one relevant transaction in child_transaction during the requested period. If there are quantities in the child_current_status view, we want those as well.
t1.field can be considered a human readable equivalent to numeric key t4.criteria.
My problem is that the query as provided fails to provide quantity data from child_current_status even when there is data there.
Edit: to clarify, the above query returns field, NULL, where it should return field, current_qty
The problem is related to the t2 subquery, because when I change that to a LEFT JOIN, it returns the relevant quantity data:
SELECT
t1.field,
SUM(v3.quantity) as current_qty
FROM
schema1.child_table t1
LEFT JOIN (SELECT DISTINCT t1key FROM schema2.child_transaction t2 WHERE datefield BETWEEN '2012-04-01' AND '2012-04-19') t2 USING (t1key)
LEFT JOIN schema1.child_current_status v3 ON t1.t1key = v3.t1key
JOIN schema1.parent_table t4 ON t1.t4key = t4.t4key
WHERE
t4.criteria = 763
GROUP BY
t1.field
Edit: this modified query returns field, current_qty, but will do so whether there are transactions in child_transaction for the requested time period or not
... all I've done is turn the first JOIN into a LEFT JOIN, and that query returns with the relevant quantities in child_current_status. If I change the child_current_status to an INNER JOIN, the query returns nothing. The problem with making the first JOIN a LEFT JOIN is that I need it to only return results when there is data returned from the sub query, which there is in this case for the requested time period.
To muddy the waters, it works properly for some t4.criteria, 763 is just one that it fails on.
What am I missing here?
Short version: From the first query above, when the first JOIN is an INNER JOIN, it causes the LEFT JOIN to return nothing. When it's a LEFT JOIN, the LEFT JOIN on child_current_status returns the proper data, but that negates the purpose of the first JOIN.
Edit: I've tried moving the LEFT JOIN to the end of the FROM clause, behind the INNER JOINs, with no change
Ugh, nevermind, I figured it out, the query is working properly and there's not enough data here for anyone else here to figure it out. Basically, there is one transaction for one child in the child_table, and there are current quantities for other children in the child_table. So the query appropriately indicates that there are no current quantities for any children for which there was a transaction during the specified time for the specified parent.
The problem came up because in processing the result of this query, I went back and asked for current data relating to all children (rather than just the ones with relevant transactions, like I should have), and got information even when this query (correctly) told me there was none.
Nothing to see here, move along.