How to script primary key constraints from existing database - sql

I have a database with 300 tables. I need to clean the tables, so I have written a script which drops all of the constraints, triggers, primary keys, and foreign keys.
I have managed to create scripts using the generate scripts feature, but they only include primary keys inside the CREATE statements.
I need to get them as ALTER TABLE statements so that I can drop the keys, clear database, insert new data, and restore all the keys, constraints, etc.

Powershell and SMO are going to be your friends here:
$option_drop = new-object Microsoft.SqlServer.Management.Smo.ScriptingOptions;
$option_drop.ScriptDrops = $true;
"" > drop_primary_keys.sql
"" > create_primary_keys.sql
$server = new-object Microsoft.SqlServer.Management.Smo.Server ".";
$db = $server.Databases['AdventureWorks'];
foreach ($table in $db.Tables) {
foreach ($index in $table.Indexes) {
if ($index.IndexKeyType -eq "DriPrimaryKey") {
$index.Script( $option_drop ) >> drop_primary_keys.sql
$index.Script() >> create_primary_keys.sql
}
}
}
A couple of notes here:
Running this script will nuke any existing files of the name "drop_primary_keys.sql" and "create_primary_keys.sql", so proceed with caution
The script doesn't take into account any foreign keys since you said you already have a way to do that.
You may have to tweak the ScriptingOptions object to fit your needs. Specifically, I'm using the defaults on the create, so you may need to create another ScriptingOptions object and set whichever options you think appropriate.
Other than that, good hunting.

Msdn has an article about disabling/enabling triggers and foreign keys:
http://msdn.microsoft.com/en-us/magazine/cc163442.aspx

Related

How to use raw SQL (DML and DDL) in Symfony projects?

I'm new in programming and I've built projects on xampp. There I created the databases in SQL (MARIADB) in 2 separated files (DML and DDL).
Now, learning Symfony I found that looks like I must use ORM to create the database. Can't I just create DML and DDL and connect/upload them to Symfony instead of using ORM?
I've been 2 days looking for information on how to do that, and I've just found ORM documentation. I wish I just could do something like this function:
function mod001_conectoBD () {
$address= "localhost";
$user= "root";
$password= "";
$database = "projectDDL"; //(which I uploaded on phpmyadmin as projectDDL.sql)
$link = mysqli_connect( $address, $user, $password, $database );
if ( !$link ) {
echo "Fail connection";
}
return $link;
}
function mod001_disconnectBD ( $link ) {
mysqli_close( $link );
}
This ofc is just the example i used on my xampp project. With this I just used the uploaded projectDDL.sql and built the app around it. Thanks and sorry for my ignorance in this matter.
The reason why I want this is building composite Primary keys, and editting id names, which i find so difficult on symfony.
Imagine for example a table that requires 3 foreign keys and its own id to have a 4 fields primary key, dont know how to make that possible in Symfony.
to connect symfony to mariadb you must modify the .env file which is at the root of your project, for your case it will give something like this:
DATABASE_URL="mysql://root#127.0.0.1:3306/projectDDL"
symfony takes care of creating the database for you, and for each table you have to create an entity
you can create your database with this command on the shell:
php bin/console doctrine:database:create
if you want to create a primary key made up of several foreign keys, doctirne allows you to do that I have already used in a project, you create an entity with foreign keys from your tables and you specify at the beginning that it is also an ID, ex :
#[Id, ManyToOne(targetEntity: User::class)]
#[Id, ManyToOne(targetEntity: Comment::class)]
#[Id, ManyToOne(targetEntity: Video::class)]
Documentation:
https://www.doctrine-project.org/projects/doctrine-orm/en/2.14/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes

Error while creating foreign relation in knex - table creation race condition

I'm new to knex and haven't touched RDBMS in years (been in NoSQL land), so bear with me here.
I've got two migration files, one for tracks and one for users (tracks are owned by users). Below are the relevant files:
migrations/20190919103115_users.js
exports.up = function(knex) {
return knex.schema.createTable('users', table => {
table.increments('id');
table.string('email', 50);
table.string('first_name', 50);
table.string('last_name', 50);
}
};
exports.down = function(knex) {
return knex.schema.dropTable('users');
};
migrations/20190406112728_tracks.js
exports.up = function(knex) {
return knex.schema.createTable('tracks', table => {
table.increments('id');
table.string('name', 140).notNullable();
table.integer('owner_id').notNullable();
table
.foreign('owner_id')
.references('id')
.inTable('users')
.onDelete('CASCADE');
table.json('metadata');
});
};
exports.down = function(knex) {
return knex.schema.dropTable('tracks');
};
When I run yarn knex migrate:up, I get:
migration file "20190406112728_tracks.js" failed
migration failed with error: alter table "tracks" add constraint "tracks_owner_id_foreign" foreign key ("owner_id") references "users" ("id") on delete CASCADE - relation "users" does not exist
I find the official Knex documentation to be pretty lacking (it's more of a reference than anything else) and can't figure out what I'm missing. Obviously I need some way for users to be created before tracks, but don't know how.
EDIT:
It seems this is how it's done: https://github.com/tgriesser/knex/issues/938#issuecomment-131491877
But it seems wrong to just put the entire set of tables in a single migration file. I thought the point was to create one migration file per table?
Migration files are sorted by name before execution, so looks like your tracks file name has an earlier date, therefore it runs before creation of users.
just run npx knex migrate:make create_users, and then npx knex migrate:make create_tracks.
it will generate new files with the proper timestamp, copy your code to the new files, delete the old ones :]

Create table Routine definition

I've been using this table INFORMATION_SCHEMA.ROUTINES which has the routine definition for procs and functions, i was wondering if there is a similar table for create table and create view routines.
I would just skip using INFORMATION_SCHEMA.ROUTINES entirely. Instead look at sys.sql_modules. It has the ddl for everything you are looking for except tables. But my question is why do you need to find the ddl for all these things?
You can use sys.sql_modules to find the definition of views. For tables, one option is SMO objects. The C# example below returns the DDL for a table in the listed database. This will require references to the Microsoft.SqlServer.Management.Sdk.Sfc, Microsoft.SqlServer.Smo, and Microsoft.SqlServer.ConnectionInfo namespaces. System.Collections.Specialized is also used, but only for StringCollection in this example. This can be filtered using the Name property of the Table class as noted below.
//set source server and database using SMO objects
Server srv = new Server(#"YourServer");
//for Windows Authentication
srv.ConnectionContext.LoginSecure = true;
srv.ConnectionContext.StatementTimeout = 600;
Database db = srv.Databases["YourDatabase"];
//configure Scripter for DDL
Scripter script = new Scripter(srv);
ScriptingOptions scriptOpt = new ScriptingOptions();
//this can changed to views, stored procedures, or other objects
foreach (Table t in db.Tables)
{
//check for system objects
//use t.Name to check table name if needed
if (!t.IsSystemObject)
{
StringCollection sc = t.Script(scriptOpt);
foreach (string s in sc)
{
//DDL is here, it can accessed/used as needed
Console.WriteLine(s);
}
}
}

TSQL | Create Database

I have two databases on my local. I wish to use tsql to script out one of the two databases in its entirety (schema only) and save it in one .sql script. Is this possible for SQL 2012? And if so, how may I go about doing it? I am using GUI to do this right now but want to use tsql query if possible. I can't use any 3rd party tools.
Thank you
UPDATE: I am using the RIGHT CLICK > GENERATE script method right now. I want to avoid that and find a way to generate the database generation tsql script by some way other than using SSMS GUI. Also, I want to script the entire database and not just tables.
You can do it in the following 2 ways.
Use Powershell.
Use the SMO classes, the Scripter class in particular. The GUI Tools are wrappers around this class.
Here's the solution for #1.
Using Powershell to Generate Table-Creation Scripts. By Robert Sheldon on simple-talk.com
Here's a solution for #2.
See this MSDN Example scripting all tables in a database with SMO.
Relevant code below. Change the database name and other details as appropriate.
//Connect to the local, default instance of SQL Server.
{
Server srv = default(Server);
srv = new Server();
//Reference the AdventureWorks database.
Database db = default(Database);
db = srv.Databases("AdventureWorks");
//Define a Scripter object and set the required scripting options.
Scripter scrp = default(Scripter);
scrp = new Scripter(srv);
scrp.Options.ScriptDrops = false;
scrp.Options.WithDependencies = true;
//Iterate through the tables in database and script each one. Display the script.
//Note that the StringCollection type needs the System.Collections.Specialized namespace to be included.
Table tb = default(Table);
Urn[] smoObjects = new Urn[2];
foreach ( tb in db.Tables) {
smoObjects = new Urn[1];
smoObjects(0) = tb.Urn;
if (tb.IsSystemObject == false) {
StringCollection sc = default(StringCollection);
sc = scrp.Script(smoObjects);
string st = null;
foreach ( st in sc) {
Console.WriteLine(st);
}
}
}
}
If you want to script out ALL the DB objects, and not just tables, take a look at the powershell script in this page where it says "Full Script". It takes care of table and relationship dependencies also.

How to clean up referenced files after a cascaded delete in an RDMS?

Zend_Db contains methods to cascade deletes and updates much like the way that most RDMS's will. The documentation states that if you are using a RDMS which supports forign keys that you should use that in place of the support in Zend_Db. The reasons for this are obvious; Zend_Db issues separate db queries for each delete/update so you lose both performance and (depending on transactional concurrency settings) atomicity.
What then is the best option given the following scenario:
A user has multiple albums, an album contains multiple photos. Each photo, album and user has a single row in equivilent db tables, however each photo is also stored on a CDN. If a user is deleted, the database cascade deletes their albums and photos. However the photos remain on the CDN and need to be removed.
maybe it would be possible to overwrite default cascade delete method with my own model's delete method but it souds like a lot of work so i've made a workaround for my project.
i have 'zadania' table and 'zadania_images' table. the second table has 'zadanie_id' column which relates the two tables.
'zadanie_images' rows contain filenames and after cascade delete of parent 'zadanie_id' the files were still there. here's my solution:
in 'Zadanie' model:
public function deleteZadanie($id) {
$row = $this->find($id)->current();
if($row) {
$image = new Model_ZadanieImage();
$image->deleteRelatedFiles($id);
$row->delete();
}
}
in 'ZadanieImage' model:
public function deleteImage($id) {
$row = $this->find($id)->current();
if($row) {
//delete the record
$filename = $row['name'];
$row->delete();
//and delete related files
unlink('images/zadanie/' . $filename);
unlink('images/zadanie/thumbs/' . $filename);
}
}
public function deleteRelatedFiles($zadanie_id) {
$select = $this->select()->where('zadanie=?', $zadanie_id);
$images = $this->fetchAll($select);
foreach($images as $image) {
$this->deleteImage($image->id);
}
}