how to extract data from a database using the primary key - delphi

I am trying to extract the Name of a person out of my database, containing two tables, with only having the ID (primary key).
I am struggling to come up with a solution, although I do have notes that I've written and the logic seems to check out (to me at least).
if P1Score > P2Score
then winner := P1ID
else winner := P2ID
winner in tblGames = the ID of winner in tblPlayers
WinnerName := first name of Winner + surname of Winner in tblPlayers
So this is my logic, obviously it's missing a lot, but I can't seem to expand on it much more
I have the ID of the person from tblGames, but now I'm struggling to understand how to use that ID to extract the Name and Surname from my tblPlayers and assign it to a variable, so I can put it into the Winner Column of tblGames.
I have tried a few things using my own thought process, but I do not know enough about Delphi and databases to actually implement it correctly.
BEGIN
if (StrToInt(P1_score) - StrToInt(P2_score) = 0) then
Draw := True
else
Draw:= False;
if StrtoInt(P1_Score) > StrToInt(P2_Score) then
winnerID := P1_ID
else
winnerID := P2_ID;
with dmTournament do
begin
tblGames.Insert;
tblGames['Player1_Id'] := StrToInt(P1_ID);
tblGames['Player2_ID'] := StrToInt(P2_ID);
tblGames['Player1_score'] := StrToInt(P1_Score);
tblGames['Player2_Score'] := StrToInt(P2_Score);
tblGames['Draw'] := Draw;
tblGames['Winner'] := WinnerName; //How do I get WinnerName(?)
tblGames.Post;
end;
END;

You don't need to do a lot of code. You can let MySQL engine do job for you. Execute the following quires in same order they appeared. This will update the table data as you want.
/* 1: Set all games to draw */
UPDATE Games SET draw = true;
/* 2: Update when Player1 is winner :*/
UPDATE Games, Players SET
Games.draw = false,
Games.winner = CONCAT(Players.first_name, ' ', Players.last_name)
WHERE
(Games.player1_score > Games.player2_score) AND (Games.player1_id=Players.ID);
/* 3: Update when Player2 is winner */
UPDATE Games, Players SET
Games.draw = false,
Games.winner = CONCAT(Players.first_name, ' ', Players.last_name)
WHERE
(Games.player2_score > Games.player1_score) AND (Games.player2_id=Players.ID);

Related

Eiffel - How do I make my classes readable?

I'm new to Eiffel and I'm trying to use the LINKED_LIST class for organizing instances of other class "MONOMIO" I've made. I added a function for ordering this elements and I use the remove and the cursor movement features and when I try to execute the code it raises an exception saying that the objects contained should be readable and writable. I would like to know how to do it, this is my class:
class
MONOMIO
feature --Initialization
make (coef:INTEGER; expX:INTEGER; expY:INTEGER)
do
coeficiente := coef
exponenteX := expX
exponenteY := expY
end
feature
evaluar(valX: INTEGER; valY: INTEGER): REAL_64
do
Result := coeficiente*(valX^exponenteX)*(valY^exponenteY)
end;
coeficiente: INTEGER;
exponenteX: INTEGER;
exponenteY: INTEGER;
feature --setter
set_coeficiente(val: INTEGER)
do
coeficiente := val
end;
end
I think the exception raises because of this feature I've made for a class that has as a feature the LINKED_LIST[MONOMIO] and it's called "contenido":
simplificar
local
tamanio_polinomio: INTEGER -- NĂºmero de monomios que tiene el polinomio
contador: INTEGER
monomio_a_comparar: MONOMIO -- Auxiliar
coeficiente_total:INTEGER -- Auxiliar
indice_monomio_en_revision:INTEGER
do
from
contenido.start
indice_monomio_en_revision := 0
tamanio_polinomio := contenido.count
until
indice_monomio_en_revision = tamanio_polinomio
loop
contenido.start
contenido.move (indice_monomio_en_revision)
monomio_a_comparar := contenido.item
from
contador := indice_monomio_en_revision
coeficiente_total := monomio_a_comparar.coeficiente
contenido.forth
until
contador = tamanio_polinomio
loop
if
(monomio_a_comparar.exponentex = contenido.item.exponentex) and
(monomio_a_comparar.exponentey = contenido.item.exponentey)
then
coeficiente_total := coeficiente_total + contenido.item.coeficiente
contenido.remove -- Mueve el cursor a la derecha
tamanio_polinomio := tamanio_polinomio - 1
contador := contador - 1
else
if
not contenido.islast
then
contenido.forth
end
end
contador := contador + 1
end
contenido.start
contenido.move (indice_monomio_en_revision)
contenido.item.set_coeficiente (coeficiente_total)
indice_monomio_en_revision := indice_monomio_en_revision + 1
end
end;
I hope anyone can help me with this problem. Thanks.
Suppose you have a list with 1 element. Then we enter the outer loop and move to the first element. Then we execute contador := indice_monomio_en_revision that is still 0 at this point and do contenido.forth. Now we are beyond the list because there is only one element. However contador = tamanio_polinomio is false (0 = 1), so we enter the inner loop and try to retrieve the second (non-existing) item. BOOM!
Other issues include:
There are multiple calls like contenido.start followed by contenido.move. You could use a single call to go_i_th instead.
Instead of counting number of items in the list I would look at the feature after. It tells when you reach an end of the list. It would simplify the logic of your loop (e.g. the call to islast would be removed) and let you to remove some local variables.
Taking the last point into account I would write the inner loop condition as
contenido.after
At least this would avoid the crash you experience. As to the logic, you may need to check features start, after, forth and remove to see what effect they have. The usual way to write loops in such cases is like
from
l.start
until
l.after
loop
... -- Use l.item
l.forth
end
In case of remove probably you do not need to call forth.

Using StringGrid selectedText in different events, delphi

Im having a form with 2 buttons with 2 different events one sets an order to be ready the other to be declined. For my stringgrid i select records from database, and for the buttonClick events i create UPDATE query, with the advStringGrid.Selectedtext which value i put in the UPDATE query. But the problem is when i first click Ready button and after that i click Decline button,without closing form, then the string value remains only until first click. Perhaps theres an option to "immediately" or w/o closing form to get new value for advStringGrid.Selectedtext variable.
procedure TfTodoList.setRefusedbtnClick(Sender: TObject);
var
i: Integer;
begin
if (Sender = setRefusedbtn) and (State = 0) then
begin
qryExec.Sql.Text := 'Update KitchenOrderRow Set StatusID = 1' +
' Where (OrderId in (Select OrderId from KitchenOrderHeader ' +
' Where Invoice = ' + IntToStr(Orders[X].Invoice) +
')) and (InvRowId = ' + IntToStr(Orders[X].InvRowId) + ')';
advOrderGridClickCell(Sender, X, Y);
end
else if (State = 1) and (setRefusedbtn = Sender) then
begin
ProductName := advOrderGrid.SelectedText;
qryExec.Sql.Text := 'Update KitchenOrderRow Set StatusID = 1' +
' where productName = ''' + ProductName + ''' and StatusID = ' +
IntToStr(qryStatusStatusID.asInteger) + '';
State := 0;
// fk_lib.logisse(nil, qryExec.Sql.Text);
end;
qryExec.ExecSQL;
advOrderGrid.RemoveSelectedRows;
end;
If you update some values in dataset which are used in DbGrid, you should refresh the dataset connected to DbCrid. Close/Open form do this.
After execution of update query do this :
Grid.Datasorce.DataSet.Refresh;
or
Grid.Datasorce.DataSet.Close;
Grid.Datasorce.DataSet.Open;
Update:
If your grid is not connected directly with database through datalink(datasource) you can refresh it as execute the same procedure which is used to fill the grid with data.

Using TIBDataset how do I set a DateTime field to null

TField.Clear does not work on a DateTime field, like it does for say an integer field.
So how do I set the field to null?
I'm using Delphi 2010.
Currently I do this;
IBDataset1.FieldByName('EUL_START_DATE').Clear;
However the field does not get set to null, it still contains a date value.
I think this explains it, but i don't want to go messing with core delphi files.
http://qc.embarcadero.com/wc/qcmain.aspx?d=78920
What if i need to reinstall Rad Studio. I would have to remember all these little patches.
In the unit IBCustomDataset from line 3480 comment out the following lines;
//if TIBStringField(Field).EmptyAsNull then
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := True
//else
//begin
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataLength := 0;
// rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := False;
//end
and add in the following lines;
//NewCode IbCustomDataSet.pas Line 3480
begin
if (Field is TIBStringField) and
(not TIBStringField(Field).EmptyAsNull) then
begin
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdDataLength := 0;
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := False;
end
else
rdFields[FMappedFieldPosition[Field.FieldNo - 1]].fdIsNull := True;
end
//End New Code
solution found here;
http://qc.embarcadero.com/wc/qcmain.aspx?d=78920
Tested, seem to work ok.
Just remember to make a note if you need to reinstall rad studio, this patch will need to be re-applied.

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?

Cant find simple error in Delphi Insertion Sort algorithm

I am using insertion sort to sort a stringlist (EmailingListArray below).
EmailingListArray[1] is an array that contains names.
EmailingListArray[2] contains corresponding emails.
I am sorting EmailingListArray[1] and when something changes within it, it also changes the second array, so they are sorted together.
An awkward way of doing things, I know, but it's for coursework and I wanted to put an insertion sort in somewhere to try get an extra mark :L
Here's my code
//quick check to make sure array contains correct values
for first := 0 to EmailingListArray[1].Count do
ShowMessage(EmailingListArray[1][first]);
//then sort
First := 0;
Last := EmailingListArray[1].Count;
for CurrentPointer := First +1 to Last-1 do
begin
CurrentValue := EmailingListArray[1][CurrentPointer];
CurrentValue2 := EmailingListArray[2][CurrentPointer];
Pointer := CurrentPointer + 1;
while ((EmailingListArray[1][Pointer] > CurrentValue) AND (Pointer > 0)) do
begin
EmailingListArray[1][Pointer+1] := EmailingListArray[1][Pointer];
EmailingListArray[2][Pointer+1] := EmailingListArray[2][Pointer];
pointer := Pointer -1;
end;
EmailingListArray[1][Pointer + 1] := CurrentValue;
EmailingListArray[2][Pointer + 1] := CurrentValue;
end;
//show message at the end for a check
ShowMessage('hello?');
The message "hello?" isn't being displayed for some reason :S.
The program isn't crashing or anything so it really should atleast display "hello?" at the end.
It isn't sorting my arrays either.
Neither am I sure if the algorithm is written correctly, I got it out of our textbook.
Any help would be much appreciated!
If you want to get a good mark:
Avoid giving misleading names for your variables:
CurrentPointer should be called CurrentIndex or CurrentPosition as it is an index and not a Pointer
Pointer is to be avoided (reserved for Pointer type) and more so because it is not a Pointer; should be WorkIndex or WorkPosition
Read the Insertion sort algorithm (wikipedia has a simple pseudocode for array indexed from 0) and implement it properly:
WorkIndex := CurrentIndex - 1; // - not + in your "Pointer := CurrentPointer + 1;"
Get your Index range from 0 to Count-1 for a TStrings.
Don't mix up the 2 arrays:
EmailingListArray[2][WorkIndex + 1] := CurrentValue2; // not CurrentValue
Update: Missed the bad while condition for zero based array.
2bis. While condition should be with >=0, not >0
while ((EmailingListArray[1][WorkIndex] > CurrentValue) AND (WorkIndex >= 0)) do

Resources