How to Compare my sql columns dynamically - compare

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.

Related

I have to add a column permissions which is determined by columns roles and access. I'm trying to nest the if loops but there is error

The code i'm using is like this
CREATE TABLE EMPLOYEE (
empId INTEGER PRIMARY KEY,
username TEXT NOT NULL,
userrole TEXT NOT NULL,
roles TEXT NOT NULL,
accesses TEXT NOT NULL
);
INSERT INTO EMPLOYEE VALUES (0001, 'Clark','President', 'Admin','privileged');
INSERT INTO EMPLOYEE VALUES (0002, 'Dave','sales rep', 'Operational role','not privileged');
INSERT INTO EMPLOYEE VALUES (0003, 'Ava','finance manager', 'Managerial role','privileged');
SELECT * FROM EMPLOYEE;
ALTER TABLE EMPLOYEE
ADD COLUMN permissions VARCHAR;
DO
$do$
BEGIN
IF EMPLOYEE.roles='Admin' THEN
IF EMPLOYEE.accesses='privileged' THEN
SET permissions = 'GRANTED';
else
IF EMPLOYEE.roles='Operational role' THEN
IF EMPLOYEE.accesses='not privileged' THEN
SET permissions = 'GRANTED';
else
IF EMPLOYEE.roles='Managerial role' THEN
IF EMPLOYEE.accesses='not privileged' THEN
SET permissions = 'GRANTED';
else
SET permissions = 'REVOKED';
END IF;
END
$do$;
SELECT * FROM EMPLOYEE;
Do you need in this:
SELECT *,
CASE WHEN (roles, accesses) IN ( ('Admin','privileged'),
('Operational role','not privileged'),
('Managerial role','not privileged') )
THEN 'GRANTED'
ELSE 'REVOKED'
END AS permissions
FROM employee;
?

Error 1452 Child Error. Stumped Please Help, Exam on this today

Here is my forward engineering script after creating the ER diagram:
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
DROP SCHEMA IF EXISTS `jocubooks` ;
CREATE SCHEMA IF NOT EXISTS `jocubooks` DEFAULT CHARACTER SET utf8 ;
USE `jocubooks` ;
DROP TABLE IF EXISTS `book` ;
CREATE TABLE IF NOT EXISTS `book` (
`ISBN` BIGINT(13) UNSIGNED NOT NULL,
`title` VARCHAR(100) NOT NULL,
`edition` VARCHAR(5) NULL,
`pubYear` YEAR NOT NULL,
PRIMARY KEY (`ISBN`),
UNIQUE INDEX `ISBN_UNIQUE` (`ISBN` ASC))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `borrower` ;
CREATE TABLE IF NOT EXISTS `borrower` (
`borrowerId` INT NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(50) NULL,
`lastName` VARCHAR(50) NOT NULL,
PRIMARY KEY (`borrowerId`),
UNIQUE INDEX `borrowerId_UNIQUE` (`borrowerId` ASC))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookStatus` ;
CREATE TABLE IF NOT EXISTS `bookStatus` (
`statusID` INT(2) NOT NULL,
`status` VARCHAR(45) NOT NULL,
PRIMARY KEY (`statusID`))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookCopy` ;
CREATE TABLE IF NOT EXISTS `bookCopy` (
`bookId` INT NOT NULL AUTO_INCREMENT,
`loanPeriod` INT(3) NOT NULL DEFAULT 30 COMMENT 'in days',
`statusId` INT(2) NOT NULL,
`ISBN` BIGINT(13) UNSIGNED NOT NULL,
PRIMARY KEY (`bookId`),
INDEX `fk_bookCopy_bookStatus_idx` (`statusId` ASC),
INDEX `fk_bookCopy_book1_idx` (`ISBN` ASC),
CONSTRAINT `statusID`
FOREIGN KEY (`statusId`)
REFERENCES `bookStatus` (`statusID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_bookCopy_book1`
FOREIGN KEY (`ISBN`)
REFERENCES `book` (`ISBN`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookLoan` ;
CREATE TABLE IF NOT EXISTS `bookLoan` (
`loanID` INT NOT NULL AUTO_INCREMENT,
`loanDate` DATE NOT NULL,
`returnDate` DATE NULL,
`borrowerId` INT NOT NULL,
`bookId` INT NOT NULL,
PRIMARY KEY (`loanID`),
INDEX `fk_bookLoan_borrower1_idx` (`borrowerId` ASC),
INDEX `fk_bookLoan_bookCopy1_idx` (`bookId` ASC),
CONSTRAINT `borrowerId`
FOREIGN KEY (`borrowerId`)
REFERENCES `borrower` (`borrowerId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_bookLoan_bookCopy1`
FOREIGN KEY (`bookId`)
REFERENCES `bookCopy` (`bookId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
I then try to create triggers to help update some of the tables:
use jocubooks;
create trigger trigChangeStatus after insert on bookloan for each row
update bookcopy set statusID = 1 where bookId = NEW.bookId;
create trigger trigChangeStatusRet after update on bookloan for each row
update bookcopy set statusID = 0 where bookId = NEW.bookId;
I run into my child row error here, I have tried using 16 in the first Null value, thought it might have been auto increment:
Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (jocubooks.bookloan, CONSTRAINT borrowerId FOREIGN KEY (borrowerId) REFERENCES borrower (borrowerId) ON DELETE NO ACTION ON UPDATE NO ACTION)
insert into bookloan values (NULL, DATE(NOW()), NULL, 5, 8);
update bookloan set returnDate = DATE(NOW()) where loanId = 3;
SELECT * FROM bookcopy;

Insert main table's primary key into child table multiple times

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?

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;

How can I re-use a MySQL++ query object to call multiple stored procedures?

#include <iostream>
#include <mysql++.h>
using namespace std;
int main() {
// Get database access parameters from command line
const char* db = "enet", *server = "192.168.1.108", *user = "root", *pass =
"123456";
// Connect to the sample database.
mysqlpp::Connection conn(false);
conn.set_option(new mysqlpp::MultiStatementsOption(true));
if (conn.connect(db, server, user, pass)) {
mysqlpp::Query query = conn.query();
query << "call CreateTable('test1', 'generic', 0, 1, 2, 3,4,5,6,7,8,9,10,NOW());";
query.execute();
query.reset();
query << "call CreateTable('test2', 'generic', 0, 1, 2, 3,4,5,6,7,8,9,10,NOW());";
query.execute();
query.reset();
return 0;
} else {
cerr << "DB connection failed: " << conn.error() << endl;
return 1;
}
return 0;
}
I want to use mysql++ query to execute procedure "CreateTable" many times, and i reset the query at last, but no matter how, just the first query works, the last does not, my problem is that:
how to make all of queries work?
-- create table --
delimiter $$
drop procedure if exists CreateTable $$
create procedure CreateTable(
IN tableName VARCHAR(20),
IN dbName VARCHAR(20),
IN INT_RegDevID INTEGER,
IN Dec_Long DECIMAL(24,16),
IN Dec_Lat DECIMAL(24,16),
IN Dec_Height DECIMAL(10,6),
IN Dec_Direction DECIMAL(10,6),
IN AverageSpeed DECIMAL(10,6),
IN Dec_Base VARCHAR(10),
IN MCC INTEGER,
IN MNC INTEGER,
IN LAC INTEGER,
IN CI INTEGER,
IN Dec_LocaDate TIMESTAMP)
-- -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------
begin
-- the test variable
-- Warning: the encoding can result many problem!!!
declare varTableName VARCHAR(32) default NULL;
set #varTableName = NULL;
set #table_prefix = "posinfo_";
set #table_params = "(
`Int_LocaID` int(11) NOT NULL auto_increment,
`INT_RegDevID` int(11) NOT NULL default '0',
`Dec_Long` decimal(24,16) NOT NULL default '0.0000000000000000',
`Dec_Lat` decimal(24,16) NOT NULL default '0.0000000000000000',
`Dec_Height` decimal(10,6) NOT NULL default '0.000000',
`Dec_Direction` decimal(10,6) NOT NULL default '0.000000',
`Dec_ MaxSpeed` decimal(10,6) NOT NULL default '0.000000',
`Dec_ MinSpeed` decimal(10,6) NOT NULL default '0.000000',
`AverageSpeed` decimal(10,6) NOT NULL default '0.000000',
`Var_PosInfo` varchar(50) character set latin1 NOT NULL default '',
`Var_Remark` varchar(200) character set latin1 NOT NULL default '',
`Date_LocaDate` timestamp NOT NULL default CURRENT_TIMESTAMP,
`Dec_Base` varchar(10) character set latin1 NOT NULL,
`MCC` int(11) NOT NULL COMMENT '',
`MNC` int(11) NOT NULL COMMENT '',
`LAC` int(11) NOT NULL COMMENT '',
`CI` int(11) NOT NULL COMMENT '',
PRIMARY KEY (`Int_LocaID`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=gbk;";
set #varCreate = CONCAT("create table ", dbName,".",#table_prefix, tableName, #table_params);
-- the insert operation
set #insertOperation = CONCAT("insert into ", dbName,".",#table_prefix, tableName,
"(INT_RegDevID,Dec_Long,Dec_Lat,Dec_Height,Dec_Direction,AverageSpeed,
Dec_Base,MCC,MNC,LAC,CI,Date_LocaDate) values(",INT_RegDevID,",",Dec_Long,
",",Dec_Lat,",",Dec_Height,",",Dec_Direction,",",AverageSpeed,",",Dec_Base,
",",MCC,",",MNC,",",LAC,",",CI,",NOW())");
-- find the target table
-- Look care about the "' '" !
set #getTargetTable = CONCAT("select TABLE_NAME into #varTableName from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='",
dbName, "' and TABLE_NAME='", #table_prefix, tableName,"'");
-- -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------
PREPARE getTargetTable from #getTargetTable;
execute getTargetTable;
select #varTableName;
set varTableName = #varTableName;
if varTableName is NULL then
-- create new table
PREPARE newTable
from #varCreate;
execute newTable;
-- do insert operation
PREPARE insertOperation
from #insertOperation;
execute insertOperation;
else
-- do insert operation
PREPARE insertOperation
from #insertOperation;
execute insertOperation;
end if;
end $$
delimiter ;
above, are the procedure.
There are several bugs here:
You've turned off exceptions (conn(false)) but you're also not checking return values for error codes. Your second execute() call is failing, but without asking the Query object why, you're running blind.
Instead of adding error checking to all MySQL++ calls, though, I think it's cleaner to allow MySQL++ to throw exceptions (conn()) and wrap the whole thing in a try block.
You don't need the MultiStatementsOption to do what you're asking the way you currently show. You have two separate statements here, not one compound statement. That in combination with the semicolons may be confusing MySQL, which is why the second call fails.
The mysql command line tool demands semicolons to terminate SQL statements, but when using a database API like MySQL++, they're only necessary to separate multiple statements.
You can either combine both CREATE statements into a single string (and one execute()) or you can drop the semicolons and the MultiStatementsOption.
The reset() calls between queries haven't been necessary since MySQL++ 2.x. The only reason the method is still available is that it's necessary if you want to reuse a Query object that had been used for template queries; they're the only type that still don't auto-reset, for fairly obvious reasons.