Appending image ID to image file name in SQL Server - sql-server

by using xp_dirtree and by doing some work around am able to get all the images into a temporary table and now i have to insert the same into main table with identity column ImageID and at the same time i have to append the same imageid to starting of the image file name added with '_' original file name
am using a query something like to insert main table
insert into tblImage(ImagePath)
SELECT fullpath + '\' + subdirectory
FROM #Directory ORDER BY fullpath,subdirectory;
currently am using loops in c# dot net to do so .... as inserting one image getting image id (scope_identity) and appending it to the file name.
but it taking large time as number of images increases.
Is there any better way to accomplish this in sql server only.

Assuming after the insert, the data in tblImage will look something like this?
ImageID ImagePath
1 somefilename.jpg
2 someotherfilename.jpg
The identity value will only be available after the insert, so you can do a bulk update after the initial bulk insert. The identity value is not available during an insert.
UPDATE tblImage SET
ImagePage = CONVERT(VARCHAR(10), ImageId) + ImagePath
WHERE (You'll have to specify a where clause to limit the update to the newly created records)
or you can add a 3rd column to tblImage
UPDATE tblImage SET
NewFileName = CONVERT(VARCHAR(10), ImageId) + '_' + ImagePath
WHERE NewFileName IS NULL
if you need to change the filename on disk, I can think of two possible solutions.
The first and quickest to implement, would be to use xp_cmdshell execute the rename statements. (this assumes ImagePage has the original filename, and NewFileName has the new filename.)
DECLARE #Cmd NVARCHAR(MAX) = '';
SELECT #Cmd = #Cmd + 'EXEC xp_cmdshell ''rename "' + ImagePath + '" "' + NewFileName + '"''
'
FROM tblImage
EXEC (#CMD);
To use xp_cmdshell, you need to enable if first, as it's disabled by default.
EXEC sp_configure 'xp_cmdshell', 1
GO
RECONFIGURE
GO
The second option to rename files on disk would be to setup a FileTable in SQL Server that points to the directory containing the files you want to rename. Then the renaming of the file becomes a simple update statement.
You can read more about FileTables here
There's also a couple of really comprehensive walkthroughs about setting up FileTables.
Hope that helps.

Related

How to delete historical SQL server database snapshot

I have a CI/CD pipeline that creates a snapshot every time it's run. Now I want to achieve something like Delete all previous snapshots and create the new one or maybe I want to delete all previous backups and save the last two or three recent snapshots only.
I have created a snapshot with the name by appending the timestamp.
As of now, I am able to find only one command which is drop database snapshot name so not sure whether it's even possible to delete all historical snapshots somehow...
Edit :
Running below code does the kind of require job any idea how can I translate the same into PowerShell script so that I can run into pipeline?
DECLARE #Sql as NVARCHAR(MAX) = (SELECT 'DROP DATABASE ['+ name + ']; ' FROM sys.databases WHERE name like '%Dev%' FOR XML PATH('')) EXEC sys.sp_executesql #Sql

Import images from folder into SQL Server table

I've being searching for this on google but I haven't found any good explanation, so here's my issue.
I need to import product images, which are in a folder to SQL Server, I tried to use xp_cmdshell but without success.
My images are in C:\users\user.name\Images and the images have their names as the product id, just like [product_id].jpg and they're going to be inserted in a table with the product ID and the image binary as columns.
I just need to list the images on the folder, convert the images to binary and insert them in the table with the file name (as the product_id)
My questions are:
How do I list the images on the folder?
How do I access the folder with dots in their name (like user.name)
How do I convert the images to binary in order to store them in the database (if SQL Server doesn't do that automatically)
Thanks in advance
I figured I'd try an xp_cmdshell-based approach just for kicks. I came up with something that does appear to work for me, so I'd be curious to know what problems you ran into when you tried using xp_cmdshell. See the comments for an explanation of what's going on here.
-- I'm going to assume you already have a destination table like this one set up.
create table Images (fname nvarchar(max), data varbinary(max));
go
-- Set the directory whose images you want to load. The rest of this code assumes that #directory
-- has a terminating backslash.
declare #directory nvarchar(max) = N'D:\Images\';
-- Query the names of all .JPG files in the given directory. The dir command's /b switch omits all
-- data from the output save for the filenames. Note that directories can contain single-quotes, so
-- we need the REPLACE to avoid terminating the string literal too early.
declare #filenames table (fname varchar(max));
declare #shellCommand nvarchar(max) = N'exec xp_cmdshell ''dir ' + replace(#directory, '''', '''''') + '*.jpg /b''';
insert #filenames exec(#shellCommand);
-- Construct and execute a batch of SQL statements to load the filenames and the contents of the
-- corresponding files into the Images table. I found when I called dir /b via xp_cmdshell above, I
-- always got a null back in the final row, which is why I check for fname IS NOT NULL here.
declare #sql nvarchar(max) = '';
with EscapedNameCTE as (select fname = replace(#directory + fname, '''', '''''') from #filenames where fname is not null)
select
#sql = #sql + N'insert Images (fname, data) values (''' + E.fname + ''', (select X.* from openrowset(bulk ''' + E.fname + N''', single_blob) X)); '
from
EscapedNameCTE E;
exec(#sql);
I started with an empty Images table. Here's what I had after running the above:
Now I'm not claiming this is necessarily the best way to go about doing this; the link provided by #nscheaffer might be more appropriate, and I'll be reading it myself since I'm not familiar with SSIS. But perhaps this will help illustrate the kind of approach you were initially trying for.

Create database table with current date as tablename

I want to create a database table with current date as tablename using sql query
In SQL Server you can name a table basically anything you want by enclosing it in [].
So generate dynamic sql and execute it:
EXEC sp_executesql N'create table [12/10/2014] (ab varchar(10));'
Further you can get the whole thing dynamically:
DECLARE #sql NVARCHAR(MAX) = 'create table [' + CONVERT(nvarchar(30), GETDATE(), 101) + '] (ab varchar(10))'
EXEC sp_executesql #sql
EDIT: This was originally tagged as MySQL so here is the solution for that as well, because I was curious.
SELECT DATE_FORMAT(CURDATE(), '%m/%d/%Y');
SET #SQL =CONCAT('CREATE TABLE `' ,DATE_FORMAT(CURDATE(), '%m/%d/%Y'), '` (id int(10))');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Though I think it's not a good option, You can get the current date from C# using
DateTime.Today
It can look like
using (SqlConnection con = new SqlConnection(conStr))
{
try
{
con.Open();
using (SqlCommand command = new SqlCommand("CREATE TABLE " + "someNamingPrefixHere_" + DateTime.Today + " (ab varchar(10));", con))
command.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
first:
do you really need to create a table that has a name as current date? why not create only a table and add a field that is a date and keep adding your data filling the date field with the current date?
if you really need to create many tables then:
you can't have a table name with the "/" character, you will have to replace those with something that is accepted by MySQL or SQLServer.
anyway to get the current date in c# use the DateTime.Now Property in c# and then you can format it using the DateTime.ToString Method (String) passing the format you wish to use like:
string tableName = DateTime.Now.ToString("ddMMyyyy");
this will give you a result like "29102014" if it's 29th october 2014.
then you can create the sql statement using the sql syntax from MySQL or SQLServer, open a connection, execute the command and then close the connection.
You should seriously learn about some SQL design practices. One file should be a row, but one day shouldn't be a whole table. I can't provide any specific answer with this description of your "problem", but easiest way would be just add another column "date" and that's it. Finished work. It's insane to have a table for each day.
This is how I obtained a table name with date and time like MY_TABLE_2019-03-25_08h45m32s687 in MS SQL server:
DECLARE #MIGRATION_TABLE_1 VARCHAR(100);
SET #MIGRATION_TABLE_1= convert(varchar(25), getdate(),121);
SET #MIGRATION_TABLE_1=REPLACE(#MIGRATION_TABLE_1,' ','_');
SET #MIGRATION_TABLE_1=STUFF(#MIGRATION_TABLE_1,14,1,'h')
SET #MIGRATION_TABLE_1=STUFF(#MIGRATION_TABLE_1,17,1,'m')
SET #MIGRATION_TABLE_1=STUFF(#MIGRATION_TABLE_1,20,1,'s')
SET #MIGRATION_TABLE_1='MY_TABLE_'+#MIGRATION_TABLE_1;
The STUFF function calls are for replacing the , : and . in the default date format
2019-03-25 08:45:32.687 to
2019-03-25_08h45m32s687
At this stage, you can display the content of the variable #MIGRATION_TABLE_1 with
SELECT #MIGRATION_TABLE_1 AS VARCHAR;
Then, you have to use the variable name into an EXEC statement as everything has to be dynamic, for example :
EXEC('CREATE TABLE ' + #tablename + ' REST OF YOUR ARGUMENTS);

How to export a SQL Server 2008 Database Diagram to another DB?

I use the handy Database Diagramming tool in SQL Server 2008 for creating and managing relationships. I have exported the sourceDB to the destinationDB but the diagram doesn't come across.
I am looking around trying to figure out how to export just the diagram I have in one database to another... This online KB article fails since select * from dtproperties doesn't exist anymore.
#Ash I was having the same problem. Here's what we did to get around it...
It seems that System Diagrams are stored within the "sysdiagrams" table. So the first thing you need to do is determine the diagram_id of the Diagram you wish to copy. Run the following query to list them all. ** Note you need to replace "SourceDB" with the name of your database.
-- List all database diagrams
SELECT * FROM [SourceDB].[dbo].sysdiagrams
Then you can use INSERT to duplicate the diagram from one database to another as follows. ** Note again replace "SourceDB" with the name of the Database containing the existing diagram and "DestinationDB" with the name of the Database you wish to copy to. Also #SourceDiagramId should be set to the id retrieved above.
-- Insert a particular database diagram
DECLARE #SourceDiagramId int = 1
INSERT INTO [DestinationDB].[dbo].sysdiagrams
SELECT [name],diagram_id , version,definition from [SourceDB].[dbo].sysdiagrams
WHERE diagram_id = #SourceDiagramId
Then you need to set the "principal_id" to 1 manually.
-- Update the principal id (no idea why, but it set the owner as some asp_net user
UPDATE [DestinationDB].[dbo].sysdiagrams
SET principal_id = 1
This worked for us it seems pretty hacky especially since the Diagram is stored entirely in a single binary field "definition".
Answer comes from:
http://www.dotnetspider.com/resources/21180-Copy-or-move-database-digram-from-for.aspx
This generates an import string:
SELECT
'DECLARE #def AS VARBINARY(MAX) ; ' +
'SELECT #def = CONVERT(VARBINARY(MAX), 0x' + CONVERT(NVARCHAR(MAX), [definition], 2) + ', 2) ;' +
' EXEC dbo.sp_creatediagram' +
' #diagramname=''' + [name] + ''',' +
' #version=' + CAST([version] AS NVARCHAR(MAX)) + ',' +
' #definition=#def'
AS ExportQuery
FROM
[dbo].[sysdiagrams]
WHERE
[name] = '' -- Diagram Name
Next, you run the generated string in other DB.
As PROCEDURE:
-- =============================================
-- Author: Eduardo Cuomo
-- Description: Export Database Diagrama to SQL Query
-- =============================================
CREATE PROCEDURE [dbo].[Sys_ExportDatabaseDiagram]
#name SYSNAME -- Diagram Name
AS
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
'DECLARE #def AS VARBINARY(MAX) ; ' +
'SELECT #def = CONVERT(VARBINARY(MAX), 0x' + CONVERT(NVARCHAR(MAX), [definition], 2) + ', 2) ; ' +
' EXEC dbo.sp_creatediagram' +
' #diagramname=''''' + [name] + ''''',' +
' #version=' + CAST([version] AS NVARCHAR(MAX)) + ',' +
' #definition=#def'
AS ExportQuery
FROM
[dbo].[sysdiagrams]
WHERE
[name] = #name
You can get rid of the UPDATE statement by fixing your INSERT statement - specifically the select portion. You are inserting the diagram_id column into the principal_id column (diagram_id is an identity).
Change it to:
DECLARE #SourceDiagramId int = 1
INSERT INTO [DestinationDB].[dbo].sysdiagrams
SELECT [name],principal_id,version,definition from [SourceDB].[dbo].sysdiagrams
WHERE diagram_id = #SourceDiagramId
And presto, it's all in there right the first time.
As in C Isaze answer, there are three simple steps:
1- Create the same number of "dummy" diagrams in the target server where you want to copy the diagrams
2- Add the target server as a Linked Server in the source server
3- run this script on source server
update [LINKEDSERVER].TARGETDB.[dbo].sysdiagrams set [definition]=
(SELECT [definition] from SOURCEDB.[dbo].sysdiagrams WHERE diagram_id = 1)
where diagram_id=1
If the databases are in different servers, there may be permission issues.
To copy the sysdiagrams, create the same number of "dummy" diagrams in the target server where you want to copy the diagrams, add the target server as a Linked Server in the source server and then run the script:
SELECT * from [LINKEDSERVER].TARGETDB.[dbo].sysdiagrams
SELECT * from SOURCEDB.[dbo].sysdiagrams
update [LINKEDSERVER].TARGETDB.[dbo].sysdiagrams set definition=
(SELECT definition from SOURCEDB.[dbo].sysdiagrams WHERE diagram_id = 1)
where diagram_id=1
-- the first 2 select commands will confirm that you are able to connect to both databases
-- then change the id as required to copy all the diagrams
There's a tool for exporting the diagrams to file and back into a database that you can find here: https://github.com/timabell/database-diagram-scm/
You'd be able to use this by pointing it at your original database and doing an export, and then pointing at your target database and doing an import.

Fetch the all the column except one

I want to fetch all the columns except one column,Can anybody help me how I can get the result except write all the column name,because it is good for less number of columns but if the table have more than 100 column then it will be very lengthy.......
For this you need to execute dynamic-SQL. You can create a function which will return you the column names or you can do something like
DECLARE #ColList Varchar(1000), #SQLStatment VARCHAR(4000)
SET #ColList = ''
select #ColList = #ColList + Name + ' , ' from syscolumns where id = object_id('Table1') AND Name != 'Column20'
SELECT #SQLStatment = 'SELECT ' + Substring(#ColList,1,len(#ColList)-1) + ' From Table1'
EXEC(#SQLStatment)
here is the link for this example -
http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/39eb0314-4c2f-4e07-84c8-e832499049f8
If this is a frequent need, I'd create a view that contains the columns you're interested in.
I don't believe this is possible.
This is not possible without writing another query to loop over the column names.
If you know which columns you need, you should SELECT them by name.
If not, you should SELECT *.
You have to list all the names I'm afraid. Assuming this is a permanent database object (e.g. table, view) then in Management studio you can right click the object in the tree view and choose SCRIPT TABLE AS -> SELECT to avoid typing them all.
Or alternatively drag the "columns" folder into your query window to get the comma delimited list of column names added.

Resources