Is there a way to return the currently logged on ID from Netezza in a view's SQL, current_sid - sql

I have a SQL statement on Netezza that uses the following SQL to acquire the currently logged on user ID:
SELECT SESSION_USERNAME FROM _V_SESSION_DETAIL WHERE SESSION_ID=current_sid
This works great when I'm executing the SQL in a database client. However, when I implement the above SQL in a view (along with other SQL) the current_sid is replaced with the session ID I happened to have when I created the view. That SQL will then look something like:
SELECT DEFINITION_SCHEMA."_V_SESSION_DETAIL".SESSION_USERNAME FROM DEFINITION_SCHEMA."_V_SESSION_DETAIL" WHERE (DEFINITION_SCHEMA."_V_SESSION_DETAIL".SESSION_ID = 2434740
Is there a way to define a view that will get the currently logged on user's ID, not the ID that was assigned when the view was created?

Seems like Netezza Metadata functions(ex. current_sid) are not supported in with clause and would advice to remove them from with and to include them in the base query .
CREATE
OR REPLACE VIEW ADMIN.VW_PI_HRCHY_EPH AS
WITH CHAR_MASK(CHAR_MASK_CHAR) AS (
SELECT 'xxx'
FROM _V_SESSION_DETAIL LIMIT 1
)
,NUM_MASK(NUM_MASK_NUM) AS (
SELECT - 1
FROM _V_SESSION_DETAIL LIMIT 1
)
,TS_MASK(TS_MASK_TS) AS (
SELECT '1000-01-01 00:00:00'
FROM _V_SESSION_DETAIL LIMIT 1
)
SELECT CASE
WHEN SECURITY_GRP_CNT.COUNT > 0
THEN PI_HRCHY.HRCHY_LINE_ID
ELSE NUM_MASK.NUM_MASK_NUM
END AS HRCHY_LINE_ID
,CASE
WHEN SECURITY_GRP_CNT.COUNT > 0
THEN PI_HRCHY.LOCALE_CD
ELSE CHAR_MASK.CHAR_MASK_CHAR
END AS LOCALE_CD
,CASE
WHEN SECURITY_GRP_CNT.COUNT > 0
THEN PI_HRCHY.MODIFY_TS
ELSE TS_MASK.TS_MASK_TS
END AS MODIFY_TS
FROM (
SELECT COUNT(*) AS count
FROM _V_USERGROUPS
WHERE USERNAME IN (
SELECT SESSION_USERNAME
FROM _V_SESSION_DETAIL
WHERE SESSION_ID = current_sid
)
AND GROUPNAME = 'GROUP_AUTH2READ'
) SECURITY_GRP_CNT
,ADMIN.PI_HRCHY
,CHAR_MASK
,NUM_MASK
,TS_MASK
WHERE (
(PI_HRCHY.HRCHY_TYP_ID = 11)
AND (PI_HRCHY.ACTV_IND = 'Y'::"NCHAR")
);

The solution NzGuy provided solved my problem. As he stated, apparently placing the current_sid contact in the WITH clause of the SQL causes the constant to be evaluated differently than if it were placed outside the WITH. The common table expression defined outside the WITH clause resolved my problem.

Related

DRY - how to extract repeated code to...a stored function maybe?

The third line of each of these statements is exactly the same:
statement1
SELECT * FROM `uploads`
WHERE `uid` = :uid
AND `deleted` <> 1 AND `archived` <> 1
statement2
SELECT * FROM `uploads`
WHERE `folder_id` = :folder_id
AND `deleted` <> 1 AND `archived` <> 1
The third line is used in many other statements as well, lets say 30 different statements; in this contrived example it means "we get all files from an uploads table...that have not been deleted or archived". If in the future we need to add a third qualifier to it (e.g. AND uploadsuccess = 1) we would have to edit 30 different sql statements. Not DRY at all. How can we use DRY principles here, via SQL (MySQL in our case, if that is an important factor)?
Thanks for any help.
I recommend using a VIEW:
CREATE OR REPLACE VIEW uploads_current AS
SELECT * FROM `uploads
WHERE `deleted` <> 1 AND `archived` <> 1;
Then you can query it with additional conditions:
SELECT * FROM `uploads_current`
WHERE `uid` = :uid;
You can redefine the view later:
CREATE OR REPLACE VIEW uploads_current AS
SELECT * FROM `uploads
WHERE `deleted` <> 1 AND `archived` <> 1 AND uploadsuccess = 1;
Then all code that queried uploads_current will implicitly include the same condition, with no code changes required.
Read more about VIEWs: https://dev.mysql.com/doc/refman/5.7/en/create-view.html
This is a common problem, we want all data to be stored, but 99% of cases we're filtering out a certain subset of data.
The solution I usually use is to create a view with the logic in, then query against that. For example:
CREATE VIEW `uploads_view` AS
SELECT * FROM `uploads`
WHERE `deleted` <> 1
AND `archived` <> `;
SELECT * FROM `uploads_view` WHERE `uid` = :uid;
SELECT * FROM `uploads_view` WHERE `folder_id` = :folder_id

how do I join two tables sql

I have an issue that I'm hoping you can help me with. I am trying to create charting data for performance of an application that I am working on. The first step for me to perform two select statements with my feature turned off and on.
SELECT onSet.testName,
avg(onSet.elapsed) as avgOn,
0 as avgOff
FROM Results onSet
WHERE onSet.pll = 'On'
GROUP BY onSet.testName
union
SELECT offSet1.testName,
0 as avgOn,
avg(offSet1.elapsed) as avgOff
FROM Results offSet1
WHERE offSet1.pll = 'Off'
GROUP BY offSet1.testName
This gives me data that looks like this:
Add,0,11.4160277777777778
Add,11.413625,0
Delete,0,4.5245277777777778
Delete,4.0039861111111111,0
Evidently union is not the correct feature. Since the data needs to look like:
Add,11.413625,11.4160277777777778
Delete,4.0039861111111111,4.5245277777777778
I've been trying to get inner joins to work but I can't get the syntax to work.
Removing the union and trying to put this statement after the select statements also doesn't work. I evidently have the wrong syntax.
inner join xxx ON onSet.testName=offset1.testName
After getting the data to be like this I want to apply one last select statement that will subtract one column from another and give me the difference. So for me it's just one step at a time.
Thanks in advance.
-KAP
I think you can use a single query with conditional aggregation:
SELECT
testName,
AVG(CASE WHEN pll = 'On' THEN elapsed ELSE 0 END) AS avgOn,
AVG(CASE WHEN pll = 'Off' THEN elapsed ELSE 0 END) AS avgOff
FROM Results
GROUP BY testName
I just saw the filemaker tag and have no idea if this work there, but on MySQL I would try something along
SELECT testName, sum(if(pll = 'On',elapsed,0)) as sumOn,
sum(if(pll = 'On',1,0)) as numOn,
sum(if(pll ='Off',elapsed,0)) as sumOff,
sum(if(pll ='Off',1,0)) as numOff,
sumOn/numOn as avgOn,
sumOff/numOff as avgOff
FROM Results
WHERE pll = 'On' or pll='Off'
GROUP BY testName ;
If it works for you then this should be rather efficient as you do not need to join. If not, thumbs pressed that this triggers another idea.
The difficulty you have with the join you envisioned is that the filtering in the WHERE clause is performed after the join was completed. So, you would still not know what records to use to compute the averages. If the above is not implementable with FileMaker then check if nested queries work. You would then
SELECT testName, on.avg as avgOn, off.avg as avgOff
FROM ( SELECT ... FROM Results ...) as on, () as off
JOIN on.testName=off.testName
If that is also not possible then I would look for temporary tables.
OK guys... thanks for the help again. Here is the final answer. The statement below is FileMaker custom function that takes 4 arguments (platform, runID, model and user count. You can see the sql statement is specified. FileMaker executeSQL() function does not support nested select statements, does not support IF statements embedded in select statements (calc functions do of course) and finally does not support the SQL keyword VALUES. FileMaker does support the SQL keyword CASE which is a little more powerful but is a bit wordy. The select statement is in a variable named sql and result is placed in a variable named result. The ExecuteSQL() function works like a printf statement for param text so you can see the swaps do occur.
Let(
[
sql =
"SELECT testName, (sum( CASE WHEN PLL='On' THEN elapsed ELSE 0 END)) as sumOn,
sum( CASE WHEN PLL='On' THEN 1 ELSE 0 END) as countOn,
sum( CASE WHEN PLL='Off' THEN elapsed ELSE 0 END) as sumOff,
sum( CASE WHEN PLL='Off' THEN 1 ELSE 0 END) as countOff
FROM Results
WHERE Platform = ?
and RunID = ?
and Model = ?
and UserCnt = ?
GROUP BY testName";
result = ExecuteSQL ( sql ; "" ; ""
; platform
; runID
; model
; userCnt )
];
getAverages ( Result ; "" ; 2 )
)
For those interested the custom function looks like this:
getAverages( result, newList, pos )
Let (
[
curValues = Substitute( GetValue( data; pos ); ","; ¶ );
sumOn = GetValue( curValues; 2 ) ;
countOn = GetValue( curValues; 3 );
sumOff = GetValue( curValues; 4 );
countOff = GetValue( curValues; 5 );
avgOn = sumOn / countOn;
avgOff = sumOff / countOff
newItem = ((avgOff - avgOn) / avgOff ) * 100
];
newList & If ( pos > ValueCount( data); newList;
getAverages( data; If ( not IsEmpty( newList); ¶ ) & newItem; pos + 1 ))
)

CASE in WHERE clause returns Error

I'm running this code:
SELECT hID
FROM logonsHistory
WHERE aIDs NOT LIKE '%''101''%' AND
CASE src
WHEN 0 THEN
uID IN(29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481)
END
I get this error:
Incorrect syntax near the keyword 'IN'
I have no idea what's wrong.
A CASE statement is not appropriate in this case. Just use a simple OR condition:
SELECT hID
FROM logonsHistory
WHERE aIDs NOT LIKE '%''101''%'
AND (
src <> 0 -- add a COALESCE here if src can be NULL
OR uID IN(29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481)
)
... which basically is the equivalent of only applying the uID filtering if src = 0, which is what you appeared to be trying to accomplish with your query.
It sounds like you don't have to use CASE please test this
SELECT hID
FROM logonsHistory
WHERE aIDs NOT LIKE '%''101''%'
AND ( (src = 0 --scr is 0 => must have uid in the list
AND UID IN (29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481))
OR src <> 0) --else src is not 0 and there is no additional condition
i have a doubt on your not like condition have you tested it alone?
Guess this is what you are looking for
WHERE aIDs NOT LIKE '%''101''%' or
(
src = 0
AND
uID IN(29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481
)
It looks like your statement is not formatted properly. you placed a condition rather than a value to set within "When 0 then ...... END
the uID IN(29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481) you have there is a condition and shouldn't have been there
The when part of a case statement should select a single value. what you are trying to do is to check for a condition.
Or if you are checking for uid in those values, you should do
case when src = 0 then
case when uID IN (29,41,42,45,49,50,57,73,83,107,166,349,356,367,375,376,416,471,472,473,474,481)
then 'It is a Client ID'
-- add another when or else part here if required
end
else 'Not a UID and not a Client ID'
end

Conditional Clause in Where Access SQL

I'm looking to add a conditional IIf or CASE to a WHERE clause in Access SQL to add an either/or condition based upon a passed value. I've seen a couple of examples on the site, but they were a little different and I have struggled to get the code to work in my case. The code:
SELECT * FROM incHC
WHERE
incHC.repdte=(SELECT Max(repdte) AS maxDt FROM bYrs) AND
incHC.asset>0 AND
incHC.eq2<>0 AND
(
CASE WHEN recType="inst" THEN
incHC.orphan=0
ELSE
incHC.orphan<=1
END
)
Any help is much appreciated.
Unless I am missing something with your query, you should be able to do this without a CASE:
SELECT *
FROM incHC
WHERE incHC.repdte=(SELECT Max(repdte) AS maxDt FROM bYrs)
AND incHC.asset>0
AND incHC.eq2<>0
AND
(
(
recType="inst"
AND incHC.orphan=0
)
OR
(
recType<>"inst"
AND incHC.orphan<=1
)
)

Modify Return Value of SELECT-Statement (TSQL) [Optimizing query]

Problem:
A Database collumn has a Tristate (0,1,2).
Each of the values are used serversidely.
The Clientcode (which cant be changed anymore) is only able to understand '0,1'.
In the Clients view '1' is identic with '2'. So I want to change the SQL Query in the Database to return '1', if the specific value is > 0.
My current Solution is combining 2 Selects (using UNION SELECT) with different WHERE-Clauses and returning '1' or '0' as static values. Now I'm looking for a solution to 'translate' the value within only ONE SELECT statement.
This is my current Solution:
SELECT
dbo.Nachricht.NachrichtID, dbo.Nachricht.Bezeichnung, '1' AS BetrifftKontoeinrichtung,
FROM dbo.Nachricht INNER JOIN dbo.AdditionalData
ON dbo.Nachricht.NachrichtID = dbo.AdditionalData.NachrichtID
WHERE (dbo.Nachricht.NachrichtID in ( 450,439 ))
AND dbo.AdditionalData.BetrifftKontoeinrichtung > 0
UNION SELECT
dbo.Nachricht.NachrichtID, dbo.Nachricht.Bezeichnung, '0' AS BetrifftKontoeinrichtung,
FROM dbo.Nachricht INNER JOIN dbo.AdditionalData
ON dbo.Nachricht.NachrichtID = dbo.AdditionalData.NachrichtID
WHERE (dbo.Nachricht.NachrichtID in ( 450,439 ))
AND dbo.AdditionalData.BetrifftKontoeinrichtung = 0
You can use a case statement, like this:
SELECT
dbo.Nachricht.NachrichtID, dbo.Nachricht.Bezeichnung,
CASE WHEN dbo.AdditionalData.BetrifftKontoeinrichtung = 0
THEN '0' ELSE '1'
END AS BetrifftKontoeinrichtung,
FROM dbo.Nachricht
INNER JOIN dbo.AdditionalData
ON dbo.Nachricht.NachrichtID = dbo.AdditionalData.NachrichtID
WHERE (dbo.Nachricht.NachrichtID in ( 450,439 ))
Looks like you need to use CASE. A decent tutorial here
http://www.databasejournal.com/features/mssql/article.php/3288921/T-SQL-Programming-Part-5---Using-the-CASE-Function.htm
See the worked example
If you just CAST(CAST(val AS BIT) AS INT) you will get integer 0 for 0 and integer 1 for everything else.