How to get result of complex query in redbeanphp - redbean

So I have this query
$sql = "set #row_number := 0;
SELECT *
FROM (
SELECT user_id, #row_number := #row_number +1 pos
FROM user
ORDER BY plays DESC
) AS row_to_return
WHERE user_id = '{$_SESSION['user']->user_id}'";
echo $sql;
$user_pos = R::exec($sql);
Have tried to use exec, findAll, findRow - no result.

This thing did the trick:
$sql = "SELECT *
FROM (
SELECT user_id, #row_number := #row_number +1 pos
FROM user
ORDER BY plays DESC
) AS row_to_return
WHERE user_id = '{$_SESSION['user']->user_id}'";
$set_sql = 'set #row_number := 0';
R::exec($set_sql);
$user_pos = R::getRow($sql);

Related

ASP Classic Recordset In Stored Procedure -1 Recordcount

I'm working with a SQL Server stored procedure in Classic ASP with 3 parameters. I am attempting to find the recordcount, but it returns '-1'.
I saw a similar post, did what it suggested (check cursortype, and add 'set nocount on' in the stored procedure), but those changes did not impact the -1 recordcount.
Here is my code in the Classic ASP page, below.
strInterestName = request("InterestName")
strActiveDate = request("activedate")
strExpireDate = request("expiredate")
Set objCommandSec = CreateObject("ADODB.Command")
Set objRS = CreateObject("ADODB.RecordSet")
objRS.cursorlocation = 3
objRS.cursortype = adOpenStatic
With objCommandSec
Set .ActiveConnection = objConnection
.CommandText = "[01_cms_search_pg_select_news_items_4]"
.CommandType = 4
.Parameters.Append .CreateParameter("#InterestName",adVarChar,
adParamInput, 25)
.Parameters.Append .CreateParameter("#ActiveDate",adDate, adParamInput)
.Parameters.Append .CreateParameter("#ExpireDate",adDate,
adParamInput)
.Parameters("#InterestName") = strInterestName
.Parameters("#ActiveDate") = strActiveDate
.Parameters("#ExpireDate") = strExpireDate
set objRS =.Execute()
End With
Here is the code for the stored procedure, below:
ALTER PROCEDURE [dbo].[01_cms_search_pg_select_news_items_4]
#InterestName varchar(50),
#ActiveDate datetime,
#ExpireDate datetime
AS DECLARE #sql nvarchar(4000)
SELECT #sql = ' SELECT * ' +
' FROM news ' +
' WHERE ' +
' bulletin_display_indicator = ''true'' '+
' AND ' +
' website_homepg_display_indicator= ''false'' '
IF #InterestName is not null
SELECT #sql = #sql + ' AND (InterestName = #InterestName)
IF #ExpireDate is not null and #ExpireDate IS NOT NULL
SELECT #sql = #sql + ' AND (expiredate between #ActiveDate and #ExpireDate)
SELECT #sql = #sql + '; '
EXEC sp_executesql #sql, N'#InterestName varchar(50), #ActiveDate
DateTime, #ExpireDate DateTime',#InterestName, #ActiveDate,
#ExpireDate
I struggled with that for a while, then found something that works for me.
It's not pretty but it does the job.
Have your Stored Procedure return 2 recordsets: one with the table data you need followed by one with the recordcount:
SELECT <all_you_need> FROM <your_table> WHERE <your_arguments>
SELECT [myCount] = ##ROWCOUNT
Then, in your ASP file:
dim objRS, dataRS, countRS
Set objRS = CreateObject("ADODB.RecordSet")
Set dataRS = CreateObject("ADODB.RecordSet")
Set countRS = CreateObject("ADODB.RecordSet")
[your original call to the stored procedure]
set objRS =.Execute()
set dataRS = objRS
set countRS = objRS.nextrecordset()
countRS now contains a recordset with a single row and a single column named 'myCount' that you can query to get the recordcount.
dataRS contains your original dataset.
NOTE: if you don't need to know the recordcount BEFORE you process the dataset, you can simplify like this:
dim objRS, countRS
Set objRS = CreateObject("ADODB.RecordSet")
Set countRS = CreateObject("ADODB.RecordSet")
[your original call to the stored procedure]
set objRS =.Execute()
[process your dataset as you need to]
set countRS = objRS.nextrecordset()

OUTPUT variables to sp_executesql

Background: SQL Server 2008 R2
Having issues with the following. Been given a usp to "finish off", author is unavailable. It extracts data from source table, copies to target table of same name + datetime stamp in an archive db then truncates source table. Want to confirm that no errors have occurred & row counts are the same before I truncate source. As I'm using DDL a TRY CATCH combo won't work.
Following code works:
DECLARE #HostName VARCHAR(30) -- Name of server running script
DECLARE #dbName VARCHAR(30) -- Database currently connected to
DECLARE #LogText VARCHAR(255) -- Text to be logged to ArchLog table
DECLARE #NewUTMetaData VARCHAR(255) -- New tablename for UTMetaData
DECLARE #NewOutboundMessagePending VARCHAR(255) -- New tablename for OutboundMessagePending
DECLARE #NewOutboundMessageStatus VARCHAR(255) -- New tablename for OutboundMessageStatus
DECLARE #NewOutboundMessageResult VARCHAR(255) -- New tablename for OutboundMessageResult
DECLARE #NewFileMessageNonSequence VARCHAR(255) -- New tablename for FileMessageNonSequence
DECLARE #NewOutboundMessageRequest VARCHAR(255) -- New tablename for OutboundMessageRequest
DECLARE #NewOutboundMessage VARCHAR(255) -- New tablename for OutboundMessage
DECLARE #SQLQuery NVARCHAR(500)
DECLARE #return_value INT
DECLARE #Err INT = 0
DECLARE #ErrFin INT = 0
DECLARE #SQLCount NVARCHAR(255) = 'SELECT #TargetCountOUT = COUNT(*) FROM '
DECLARE #ParmDefinition nvarchar(50) = N'#TargetCountOUT int OUTPUT';;
DECLARE #SourceCount INT = 0
DECLARE #TargetCount INT = 0
-- Log message that delete is starting
SELECT #HostName = host_name()
SELECT #dbName = db_name()
SELECT #LogText = 'Procedure ArchiveMuleDBMetrix_NEW starting database= ' + #dbname + ' host= ' + #HostName
EXEC xp_logevent 50001, #LogText, 'INFORMATIONAL'
INSERT INTO [MuleDBArch].[dbo].[ArchLog]
([LogEntryDateTime]
,[LogEntry])
VALUES (GETDATE()
,#LogText)
BEGIN
SELECT #NewUTMetaData = (SELECT '[MuleDBArch].[dbo].UTMetaDataA' + convert(varchar(50),GetDate(),112) + replace(convert(varchar, GetDate(),108),':',''))
SET #err = ##error;
SET #SQLQuery = 'select * into ' + #NewUTMetaData + ' from [MuleDB].[dbo].[SASITUTMetaData]'
EXECUTE sp_executesql #SQLQuery
SET #SourceCount = ##ROWCOUNT
SELECT #LogText = 'Rows archived into ' + #NewUTMetaData + ' by Procedure ArchiveMuleDBMetrix_NEW = ' + CAST(#SourceCount as VARCHAR(6))
EXEC xp_logevent 50002, #LogText, 'INFORMATIONAL'
INSERT INTO [MuleDBArch].[dbo].[ArchLog]
([LogEntryDateTime]
,[LogEntry])
VALUES (GETDATE()
,#LogText)
IF #err = 0
BEGIN
SET #sqlcount = #sqlcount + #NewUTMetaData
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
IF #SourceCount = #TargetCount
TRUNCATE TABLE [MuleDB].[dbo].[SASITUTMetaData]
ELSE
SELECT #LogText = 'Post archive, row counts differ between [MuleDB].[dbo].[SASITUTMetaData] and' + #NewUTMetaData
EXEC xp_logevent 50003, #LogText, 'Error'
Set #errfin = 1
SET #err = 0
END
ELSE
BEGIN
SELECT #LogText = 'Procedure ArchiveMuleDBMetrix_NEW failed archiving into ' + #NewUTMetaData
EXEC xp_logevent 50004, #LogText, 'Error'
Set #errfin = 1
SET #err = 0
END
END
However, if I repeat the block to work on another table (or indeed the same one) query completes with error and I get the message:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '.'.
I think I've narrowed it down to the line:
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
Any help appreciated
In the below code
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCountOUT=#TargetCount OUTPUT;
You are trying to pass parameter values without specifying the parameter names except the output parameter while calling the stored procedure. Either specify the parameter name for all or none. Try to execute the code as follows
EXECUTE sp_executesql #sqlcount, #ParmDefinition, #TargetCount OUTPUT;

KanBan Database architecture

I'm trying to implement a kanban agile board like Trello in my application. I'm wondering how to do it the best way. I'm considering these entities:
Board
has many Lists
List
has many Cards
Card
contains some content
However I'm stuck with ordering of Cards. Each Card should have a sort position to sort Cards in particular order in a List. When dragging a Card, I should change it's position and save it in the database. What is the most efficient way of doing this?
Adding a position field to each Card seems redundant since I would have to recalculate positions of all Cards in a List (or two) after I drag a Card to a different position (there will be hundreds of Cards). I was thinking of storing an array of all Card ids in a List and sort Cards by this array. What are pros/cons of this solution? And are there any better solutions?
I'm using Ruby on Rails and PostgreSQL.
UPDATE
Using #cske answer I came up with the following solution:
CREATE OR REPLACE FUNCTION move_buyer_card(
new_list_id INT
, param_id INT
, new_position INT
) RETURNS FLOAT4
LANGUAGE plpgsql SECURITY DEFINER
AS $$
DECLARE
var_lower_bound FLOAT4;
var_upper_bound FLOAT4;
var_new_weight FLOAT4; /*between 0 and 1*/
BEGIN
IF new_position < 2 THEN /*first position*/
var_lower_bound := 0;
SELECT MIN(weight) FROM Buyers
WHERE board_list_id = new_list_id
INTO var_upper_bound;
IF var_upper_bound IS NULL THEN /*empty list*/
var_upper_bound := 1;
END IF;
ELSE /*not first position*/
WITH ordered_cards AS (
SELECT id, RANK() OVER (ORDER BY weight ASC) AS rank, weight
FROM Buyers WHERE board_list_id = new_list_id
)
SELECT cards0.weight, cards1.weight from ordered_cards cards0
JOIN ordered_cards cards1
ON cards0.rank = cards1.rank - 1
WHERE cards1.rank = new_position
INTO var_lower_bound, var_upper_bound;
IF NOT FOUND THEN /*only 1 item in list OR last position*/
SELECT MAX(weight) FROM Buyers WHERE board_list_id = new_list_id
INTO var_lower_bound;
IF var_lower_bound IS NULL THEN /*empty list*/
var_lower_bound := 0;
END IF;
var_upper_bound := 1;
END IF;
END IF;
var_new_weight := var_lower_bound + (var_upper_bound - var_lower_bound) / 2;
UPDATE Buyers
SET weight = var_new_weight,
board_list_id = new_list_id
WHERE id = param_id;
RETURN var_new_weight;
END;
$$;
Consider this, trick is not storing the position, but a weight so you can insert between any two elements
create table listOfCards (
listId INTEGER
,cardId INTEGER
,weigth FLOAT4
,PRIMARY KEY (listId,cardId)
);
CREATE OR REPLACE FUNCTION addCard(
plistId INT
, pcardId INT
, ppos INT
) RETURNS FLOAT4
LANGUAGE plpgsql SECURITY DEFINER
AS $$
DECLARE
vlb FLOAT4;
vub FLOAT4;
vnw FLOAT4;
BEGIN
IF 2 > ppos THEN
vlb := 0;
SELECT min(weigth) FROM listOfCards WHERE listId = plistId INTO vub;
IF vub IS NULL THEN /*empty list*/
vub := 2;
END IF;
ELSE
with corder as (select cardId,RANK() OVER (order by weigth asc) as r,weigth FROM listOfCards WHERE listId=1)
select c0.weigth,c1.weigth from corder c0 JOIN corder c1 ON c1.r = c0.r + 1 where c1.r = ppos INTO vlb,vub;
IF NOT FOUND THEN
SELECT max(weigth) FROM listOfCards WHERE listId = plistId INTO vlb;
IF vlb IS NULL THEN /*empty list*/
vlb := 0;
END IF;
vub := (vlb+1) * 2;
END IF;
END IF;
vnw := vlb + (vub-vlb) /2;
INSERT INTO listOfCards(listId, cardId, weigth)
VALUES (plistId,pcardId,vnw )
ON CONFLICT ON CONSTRAINT listofcards_pkey DO UPDATE SET weigth = vnw ;
RETURN vnw;
END;
$$;
Usage:
select addCard(1,1,1);
select addCard(1,2,1);
select addCard(1,3,2);
select addCard(1,4,2);
select addCard(1,5,5);
select addCard(1,5,2);
select * from listOfCards ORDER BY weigth;
Result:
1,2,0.5
1,5,0.5625
1,4,0.625
1,3,0.75
1,1,1

Use MERGE statement in a stored procedure with Informix

I have a stored procedure like this : http://tinyurl.com/pbk8qfb
CREATE PROCEDURE PS_TAB_TSEN(NOMFIC VARCHAR(70), LIBSEN VARCHAR(35),
CODAPPFOF VARCHAR(3))
DEFINE NUMINTNAV VARCHAR(10);
BEGIN;
LET NUMINTNAV = '0';
SELECT TO_CHAR(NUM_INT_NAV) INTO NUMINTNAV
FROM TAB_INAV WHERE NOM_FIC = NOMFIC;
MERGE INTO TAB_TSEN T
USING (SELECT COD_SEN, LIBSEN AS LIB_SEN, CODAPPFOF AS COD_APP_FOF
FROM TAB_TSEN
WHERE COD_SEN = NUMINTNAV) AS S
ON (T.COD_SEN = S.COD_SEN)
WHEN MATCHED THEN
UPDATE SET T.COD_SEN = S.COD_SEN, T.LIB_SEN = S.LIB_SEN,
T.COD_APP_FOF = S.COD_APP_FOF
WHEN NOT MATCHED THEN
INSERT (T.COD_SEN, T.LIB_SEN, T.COD_APP_FOF)
VALUES (S.COD_SEN, S.LIB_SEN, S.COD_APP_FOF);
COMMIT;
END PROCEDURE;
When I run it all is good, but when I check in the table I see no result, for the insert statement and for the update statement too.
I call it like this:
CALL PS_TAB_TSEN('~/PSS/Order/OrderList.aspx', 'Liste des commandes', 'NET');
I don't understand what is going on...
Problem solved, I replace my stored procedure by this one :
CREATE PROCEDURE PS_TAB_TSEN(NOMFIC VARCHAR(70), LIBSEN VARCHAR(35), CODAPPFOF VARCHAR(3))
DEFINE ISPRESENT INTEGER;
DEFINE NUMINTNAV VARCHAR(10);
BEGIN;
LET NUMINTNAV = '0';
SELECT TO_CHAR(NUM_INT_NAV) INTO NUMINTNAV FROM TAB_INAV WHERE NOM_FIC = NOMFIC;
LET ISPRESENT = 0;
SELECT COUNT(*) INTO ISPRESENT FROM TAB_TSEN WHERE COD_SEN = NUMINTNAV;
IF(ISPRESENT > 0) THEN
UPDATE TAB_TSEN SET T.COD_SEN = S.COD_SEN, T.LIB_SEN = S.LIB_SEN, T.COD_APP_FOF = S.COD_APP_FOF
ELSE
INSERT INTO TAB_TSEN (T.COD_SEN, T.LIB_SEN, T.COD_APP_FOF) VALUES (S.COD_SEN, S.LIB_SEN, S.COD_APP_FOF);
END IF;
COMMIT;
END PROCEDURE;

How to return ref_cursor from for loop from pl/sql procedure

i want to get back ref cursor for the below sp. But it's not working.. not getting any records.. So please help me for this.
DATA_INPUTLIST - it's collection type for two variables (mtn, mtnEffDate)
DATA_RESULTLIST - It's also a collection type for 3 variables (id, effDate, mtn)
CREATE OR REPLACE PROCEDURE proc1 (
pCustId IN NUMBER,
pAcctNo IN NUMBER,
pSearchCriteria IN DATA_INPUTLIST,
pRecordSet OUT SYS_REFCURSOR,
out_error_code OUT NUMBER,
out_error_message OUT VARCHAR2
) AS
--Variables
v_SUN_DATE DATE := TO_DATE('01/15/2011', 'mm/dd/yyyy');
vCount NUMBER := 0;
v_mtn NUM
BER;
v_mtn_eff_date DATE;
cMtnPricePlanInfo DATA_RESULTLIST;
BEGIN
SELECT COUNT(*) INTO vCount FROM TABLE (pSearchCriteria);
FOR i IN 1..vCount LOOP
SELECT MTN, TO_DATE(MTN_EFF_DATE, 'mm/dd/yyyy') into v_mtn, v_mtn_eff_date
FROM TABLE (pSearchCriteria)
WHERE
ROWNUM = i;
SELECT
A.PPLAN_ID, A.EFF_DATE, A.MTN INTO cMtnPricePlanInfo(i).PPLAN_ID, cMtnPricePlanInfo(i).EFF_DATE, cMtnPricePlanInfo(i).MTN
FROM CUST_ACCT_LINE_PPLAN A, CUST_ACCT_LINE_PPLAN_HIST B
WHERE
A.CUST_ID = pCustId
AND A.ACCT_NO = pAcctNo
AND A.MTN = v_mtn
AND A.MTN_EFF_DATE = v_mtn_eff_date
AND A.EFF_DATE >=
(SELECT MAX(EFF_DATE) FROM CUST_ACCT_LINE_PPLAN_HIST C
WHERE
C.CUST_ID = pCustId
AND C.ACCT_NO = pAcctNo
AND C.MTN = v_mtn
AND C.MTN_EFF_DATE = v_mtn_eff_date
AND C.EFF_DATE <= v_SUN_DATE)
AND A.CUST_ID = B.CUST_ID
AND A.ACCT_NO = B.ACCT_NO
AND A.MTN = B.MTN
AND A.MTN_EFF_DATE = B.MTN_EFF_DATE
AND A.PPLAN_ID = B.PPLAN_ID;
END LOOP;
OPEN pRecordSet FOR
SELECT * FROM TABLE (cMtnPricePlanInfo);
END;
/
The first things that stands out to me is the following:
SELECT MTN, TO_DATE(MTN_EFF_DATE, 'mm/dd/yyyy') into v_mtn, v_mtn_eff_date
FROM TABLE (pSearchCriteria)
WHERE
ROWNUM = i;
For i greater than 1 this will not return anything. For the reason why, see this question. In fact, because you're using SELECT ... INTO ..., you'll get a no data found error if i is greater than or equal to 2.
You don't need an SQL query just to fetch some values out of PL/SQL collections. Try replacing this query with
v_mtn := pSearchCriteria(i).MTN;
v_mtn_eff_date := TO_DATE(pSearchCriteria(i).MTN_EFF_DATE, 'mm/dd/yyyy');
I don't have your tables nor the data in them so I can't be sure why you're getting no data. I can only hazard at some obvious suggestions: is vCount zero? If you put suitable values for v_mtn and v_mtn_eff_date and run your query on its own, separate from this stored procedure, does it return any rows?

Resources