Insert main table's primary key into child table multiple times - c++

I have MS Access 2007 database with the following schema:
Main table Object< # Object_PK, ... >
Child table Electric_Consumption< $ Object_PK, # Electric_Consumption_PK, ... >
Child table Water_Consumption< $ Object_PK, # Water_Consumption_PK, ... >
Child table Educational_Object< $ Object_PK, # Educational_Object_PK, ... > which has child tables defined like this:
School< $ Educational_Object_PK, # School_PK, ... >
University< $ Educational_Object_PK, # University_PK, ... >
Here is the picture that should make things clearer:
I use ADO and C++ to insert data.
First I need to enter data for main table Object. I can successfully do that with INSERT query.
My problem is following:
After the above operation I need to insert Object's primary key into child tables, since it is their foreign key.
Allow me to describe exactly what I need so community can help me:
As I said, first I insert data into main table Object.
Then I need to insert data and Object's primary key into child tables.
Browsing through Internet I have found ##IDENTITY that might help me but I do not know if it works for my case.
To make things harder, this will be done in for loop ( the value of the Object_PK is the same in every INSERT and is equal to the value of the last inserted record for the Object ) , something like this:
for ( //... )
L"INSERT INTO Electric_Consumption ( Object_PK, field1, field2 ... )
values ( Object_pk // should I use here ##IDENTITY ? );
Then the same thing should be repeated for tables Water_Consumption and Educational_Object.
After I finish this, I need to add data in the Educational_Object's child tables.
The same as above, only instead of Object_PK I need to add Educational_Object_PK.
Here is the pseudo-code to clarify things better:
L"INSERT INTO Object ( ... ) values ( ... ); //this is OK
for ( ... )
L" INSERT INTO Electric_Consumption ( Object_PK, ... )
values ( Object_PK, ... )"; // should I use ##IDENTITY here
// to get Object_PK ??
for ( ... )
L" INSERT INTO Water_Consumption ( Object_PK, ... )
values ( Object_PK, ... )"; // should I use ##IDENTITY here
// to get Object_PK ??
for ( ... )
L" INSERT INTO Educational_Object ( Object_PK, ... )
values ( Object_PK, ... )"; // should I use ##IDENTITY here
// to get Object_PK ??
for ( ... )
L" INSERT INTO School ( Educational_Object_PK, ... )
values ( Educational_Object_PK, ... )";// should I use ##IDENTITY here
// to get Educational_Object_PK ??
for ( ... )
L" INSERT INTO University ( Educational_Object_PK, ... )
values ( Educational_Object_PK, ... )";// should I use ##IDENTITY here
// to get Educational_Object_PK ??
Can you please tell me which SQL statement to use for this, and demonstrate how to use it by providing a small pseudo code?
I understand that my description of the problem might be confusing so if you need further clarification leave a comment and I will edit my post.
Thank you.
Best regards.

Yes, you want to use SELECT ##IDENTITY as a multiuser-safe way to retrieve the most recently-created AutoNumber (sometimes called "IDENTITY") value. The things to remember are:
You execute a SELECT ##IDENTITY query immediately after you perform the INSERT on the parent table.
You store the returned value in a Long Integer variable.
You use the variable to populate the Foreign Key values in the child table(s).
The following is VBA code, but you can treat it as pseudo-code:
Dim lngObject_PK As Long, lngEducational_Object_PK As Long
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandText = "INSERT INTO [Object] ([Description]) VALUES (?)"
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255, "my new Object")
cmd.Execute
Set cmd = Nothing
Set rst = New ADODB.Recordset
rst.Open "SELECT ##IDENTITY", con, adOpenStatic, adLockOptimistic
lngObject_PK = rst(0).Value
rst.Close
Set rst = Nothing
Debug.Print "Object_PK of newly-created Object record: " & lngObject_PK
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandText = "INSERT INTO [Electric_Consumption] ([Object_PK],[Description]) VALUES (?,?)"
cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput, , lngObject_PK)
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255, "my new Electric_Consumption")
cmd.Execute
Set cmd = Nothing
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandText = "INSERT INTO [Educational_Object] ([Object_PK],[Description]) VALUES (?,?)"
cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput, , lngObject_PK)
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255, "my new Educational_Object")
cmd.Execute
Set cmd = Nothing
Set rst = New ADODB.Recordset
rst.Open "SELECT ##IDENTITY", con, adOpenStatic, adLockOptimistic
lngEducational_Object_PK = rst(0).Value
rst.Close
Set rst = Nothing
Debug.Print "Educational_Object_PK of newly-created Educational_Object record: " & lngEducational_Object_PK
Set cmd = New ADODB.Command
cmd.ActiveConnection = con
cmd.CommandText = "INSERT INTO [School] ([Educational_Object_PK],[Description]) VALUES (?,?)"
cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput, , lngEducational_Object_PK)
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255, "my new School")
cmd.Execute
Set cmd = Nothing

If the Object_PK is predictable, such as you are using an Autonumber field, you could first determine the next key by something like:
SELECT Max([Object_ID]+1) AS NewKey
FROM ObjectTable;
then use that for all of the other tables (or simply retrieve the MAX key value after storing the Object); How is the primary key defined?

Related

Doctrine QueryBuilder - Struggling with table 'state' variable

I have the following query and the last part of it is to check the state of the item which will be 1 or 0;
My api calls:
http://example.com/api/search?keyword=someword&search_for=item&return_product
The query works as expected, except for one thing. Some of the stone items are disabled and I need to ignore where:
->where('S.state=:state')
->setParameter('state' , 1 )
I am not quite sure where to add this to the current query to get it to work:
$qb = $this->stoneRepository->createQueryBuilder('S');
//Get the image for the item
$qb->addSelect('I')
->leftJoin('S.image' , 'I');
//Check if we want products returned
if ( $return_product )
{
$qb->addSelect('P','PI')
->leftJoin('S.product' , 'P')
->leftJoin('P.image' , 'PI');
}
//Check is we want attributes returned
if ( $return_attribute )
{
$qb->addSelect('A','C')
->leftJoin('S.attribute' , 'A')
->leftJoin('A.category' , 'C');
}
//Check the fields for matches
$qb->add('where' , $qb->expr()->orX(
$qb->expr()->like('S.name' , ':keyword'),
$qb->expr()->like('S.description' , ':keyword')
)
);
//Set the search item
$qb->setParameter('keyword', '%'.$keyword.'%');
$qb->add('orderBy', 'S.name ASC');
Just after the createQueryBuilder call:
$qb = $this->stoneRepository
->createQueryBuilder('S')
->where('S.state = :state')
->setParameter('state', 1);
With the query builder the order is not important: you can add SQL pieces in different order and even override pieces already added.

How to Compare my sql columns dynamically

I am not able to get idea about the following requirement. The example table follows.
CREATE TABLE `test` (
`Id` INT NOT NULL,
`Name` VARCHAR(45) NULL,
`did_fk` INT NULL,
`adid_fk` INT NULL,
PRIMARY KEY (`Id`));
INSERT INTO test (id,name,did_fk,adid_fk)
VALUES
(1,'Rajesh',1,1),
(2,'Neeli',2,2),
(3,'Satish',3,3),
(4,'Ganesh',4,5),
(5,'Murali',9,10);
Here I need to compare the "id" with _fk columns i.e. did_fk & adid_fk. The "id" should be equal to did_fk & as well as adid_fk. If any of them is not true, then I should get that row.Here I need to get the rows 4 & 5.Since "_fk" columns are not equal to "id" value.Problem is "_fk" columns are not fixed. But "id" name is fixed.
SELECT * FROM `test` WHERE `Id` != `did_fk` OR `Id` != `adid_fk`
If your dynamic columns ends with _fk or some another suffix you can try to create SP like following
CREATE DEFINER=`root`#`localhost` PROCEDURE `GetNonEqualFkValues`(IN tableName varchar(255))
BEGIN
DECLARE c_name VARCHAR(255);
DECLARE done INT DEFAULT FALSE;
DECLARE curs CURSOR FOR select column_name from information_schema.columns where column_name like '%_fk';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN curs;
SET #q = concat("SELECT * FROM ", tableName, " WHERE 1!=1 ");
get_col: LOOP
FETCH curs INTO c_name;
IF done THEN
LEAVE get_col;
END IF;
SET #q = CONCAT(#q, " OR ", c_name," != id");
END LOOP get_col;
PREPARE stmt1 FROM #q;
EXECUTE stmt1;
END
And then invoke for concrete table like
call GetNonEqualFkValues('test')
The code isn't perfect, but it works for me and I think idea should be clear.

How to use Last inserted id of a Table in Another Table

I have searched and realized i can use SCOPE but am not sure how to use it. Any help will be appreciated
This is Options insert statement
char sql[256];
sprintf_s(sql, "INSERT INTO Options[Value],[ValuesCorrect],[QuestionId]) VALUES ('%s', '%d', '%d'); "
, choice->getValue()
, choice->getIsAnswer()
, choice->getQuestionId());
pRecordSet->Open(sql, pConnection.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
This is my my Question Table
char sql[256];
"DECLARE #ID = BIGINT";
sprintf_s(sql, "INSERT INTO Questions([Query],[CompetencyLevel],[TopicId]) VALUES('%s', %d, %d); "
,(const char*)question->getQuery()
, question->getCompetencyLevel()
,question->getTopicId());
pRecordSet->Open(sql, pConnection.GetInterfacePtr(), adOpenForwardOnly, adLockReadOnly, adCmdText);
"SELECT#ID = SCOPE_IDENTITY();";
The following query will return the inserted id
INSERT INTO Options (
[Value]
,[ValuesCorrect]
,[QuestionId]
)
OUTPUT inserted.[YourIdColumnName]
VALUES (
'%s'
,'%d'
,'%d'
)
A long time since I used ADO but the code could look something like
pRecordSet->Open(...);
auto id = pRecordSet->Fields->Item[0]->Value;

inserting to database using ado command

I am trying to insert records into a table using adodb using c++.
Stored Proc:
CREATE PROCEDURE [dbo].[dbo.insert_command]
#Id INT OUTPUT,
#Name varchar(25),
#Age int = NULL
-- WITH ENCRYPTION
AS
...
Declaring the commands:
TESTHR(m_pInsertCommand.CreateInstance(__uuidof(Command)));
m_pInsertCommand>ActiveConnection = m_pConnection;
m_pInsertCommand>CommandText = L"dbo.insert_command";
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Id", adInteger, adParamOutput, 4, vtNull));
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Name", adVarChar, adParamInput, m_lLabelLength));
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Age", adInteger, adParamInput, sizeof(long), vtNull));
Setting the parameters:
dbConnection.m_pInsertCommand->Parameters->Item[L"Id"]->Value = vtNull;
dbConnection.m_pInsertCommand->Parameters->Item[L"Name"]->Value = (BSTR) m_Name;
dbConnection.ExecuteCommand(dbConnection.m_pInsertCommand, adCmdStoredProc | adExecuteNoRecords);
Id = (long) dbConnection.m_pInsertDefectCommand->Parameters->Item[L"Id"]->Value;
Trace through SQL Profiler:
declare #p1 int
set #p1=16
exec dbo.insert_Command #p1 output,'Name',NULL
select #p1
My question is why is the command generating the parameter #p1 in the sql statement. this is causing the logic to change as I am trying to insert a record if the parameter id is null.
Any suggestions for why this is happening?
Thanks in advance

Coldfusion: Can't reference var from query result set

Using cfscript, trying to set the ID of the newly inserted question so that I can use it in my answer insert to build the relationship. I've done this a million times outside of cfscript. setName seems to be the proper method to call to create the query name.
I'm receiving the error that "theQuestionID" does not exist in qryQuestion
i = 1;
while ( structKeyExists( form, "question" & i ) )
{
q = new Query();
q.setDatasource("kSurvey");
q.setName("qryQuestion");
q.setSQL("
set nocount on
insert into question (question)
values('#form["question#i#"]#')
select ##IDENTITY AS theQuestionID
set NOCOUNT off
");
q.execute();
writeOutput("Question"&i&"<br>");
j = 1;
while ( structKeyExists( form, "question" & i & "_answer" & j) ) {
q = new Query();
q.setDatasource("kSurvey");
q.setSQL("
insert into answer (answer,questionid)
values('#form["question#i#_answer#j#"]#',#qryQuestion.theQuestionID#)
");
q.execute();
writeOutput("Answer"&j&"<br>");
j++;
}
i++;
}
Theres a better way to accomplish this without having to select ##identity (which in itself isn't the best way to get it from sql server, using scope_identity is the best practice way to do this in sql server. http://msdn.microsoft.com/en-us/library/ms190315.aspx
Fortunately ColdFusion makes this even easier:
<cfscript>
insertQuery = new query();
insertQuery.setDatasource("datasourcename");
insertQuery.setSql("insert into contact(firstname, lastname)
values('ryan','anklam')");
result = insertQuery.Execute();
theKey = result.getPrefix().generatedkey;
</cfscript>