Multiple tables in the where clause that start with the same string - sql

I'm using sql-server 2014 and am trying to select ID values from a table where the ID values do not exist in hundreds of other tables which all start with the same string (e.g. MyTable1, MyTable2, MyTable3, etc.)
My current query is something like this...
select ID from want w
where not exists (select 'x' from MyTable1 m1 where m1.ID = w.id)
and not exists (select 'x' from MyTable2 m2 where m2.ID = w.id)
I'm looking for something like
select ID from want w
where not exists (select 'x' from 'MyTable%' m where m.ID = w.id)
Or
select ID from want w
where ID not in
(select ID from 'MyTable%')
Thank you!

You do mention that there are hundreds of other tables, is the number of tables increasing? Using INFORMATION_SCHEMA.TABLES as already mentioned in the comments in your question along with dynamic SQL would be a start but also look up cursors for looping through the table names with the result-set returned from INFORMATION_SCHEMA.TABLES. The code fragment below will loop through the table listing from information_schema on the default database. You'll have to add your own code depending on what you want to do where the 'if' statement is. The variable #Table_Name has the name of the table, so you would need to include this in a dynamic SQL string and execute this to get your unused ids.
declare #table_name varchar(256);
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME
FROM [Datasets].INFORMATION_SCHEMA.TABLES
;
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TABLE_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
if(#Table_Name like 'Airline%')
print('Have table name to work with: ' + #Table_Name);
else
print('Ignoring table: ' + #Table_name);
FETCH NEXT FROM db_cursor INTO #TABLE_NAME
END
CLOSE db_cursor
DEALLOCATE db_cursor

Related

Convert semi-colon separated codes in a column to their values SQL

I know this goes against all DB normalization principals but I cannot change the design at this point.
I have a column that has values stored like this (SQL Server database):
5;26;31;49
There's another table that has translation for this values which looks like this:
Code Value
-------------------
5 Some Value 1
26 Some Value 2
31 Some Value 3
49 Some Value 4
I need to convert the semi-colon delimited codes into their corresponding values and present these values as part of just 1 row, so what I want to see as a result is:
Some Value 1; Some Value 2; Some Value 3; Some Value 4
Does anyone have a solution for this puzzle?
Thanks.
Use string_split if you are on SQLSERVER,that transpose row to a column.The result set can be used as a table and joined with any table in the DB for desired result.
declare #str VARCHAR(20)= '5;26;31;49'
(SELECT VALUE FROM string_split(#str,';'));
When two tables are joined the result would look like the below,
select tablB.value from
(SELECT VALUE as code FROM string_split(tableA.col,';')) transposed_table,
tableB
where transposed_table.code = tableB.code
You may use cursor to loop through to transport the output to a string as below,
DECLARE #codevalues VARCHAR(max) = '';
DECLARE #codevalue VARCHAR(20)= '';
DECLARE db_cursor CURSOR FOR
select tablB.value+';' from
(SELECT VALUE as code FROM string_split(tableA.col,';')) transposed_table,
tableB
where transposed_table.code = tableB.code;
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #codevalue
WHILE ##FETCH_STATUS = 0
BEGIN
set #codevalues = #codevalues+#codevalue;
FETCH NEXT FROM db_cursor INTO #codevalue
END
CLOSE db_cursor
PRINT #codevalues;
DEALLOCATE db_cursor
In the most recent versions of SQL Server, you can use string_split() and string_agg():
select t.*, v.expanded
from t cross apply
(select string_agg(c.value, ';') within group (order by charindex(c.code, t.codes) as expanded
from string_split(t.codes, ';') join
codes c
on c.code = s.value
) v;

Simple Sql Procedure with/without cursor

Please help me with a simple procedure, lets say on Sql Server (2005, 2008, does not matter).
I have table dbo.[columns] with 1000 lines, which all are the names for some specific table names from a database.
Bottom line is that I need to create a procedure which will parse all 1000 lines of tables,
for each table name found in dbo.[columns] to execute the following
select: select count(*), ''''+[column_name]+'''' from dbo.[column_name]
The result should be like this:
count(*) table_name:
100 employees
0 ex_employees
25 addresses
10 birthdays
Any hints?
Thanks in advance,
Bogdan
SELECT COUNT(Column_With_List_Of_Table_Names_Here)
, Column_With_List_Of_Table_Names_Here
FROM YourDatabase.dbo.YourTable
GROUP BY Column_With_List_Of_Table_Names_Here;
Maybe not what are you asking, but should get the results I think you want. You can use system views to get the row count for each table without running COUNT(*)
SELECT i.rowcnt, o.name FROM sysindexes i
LEFT JOIN sys.objects o ON i.id = o.object_id
WHERE indid <2
ORDER BY name
or
SELECT SUM (row_count) AS ROWS, o.Name AS TableName
FROM sys.dm_db_partition_stats s
LEFT JOIN sys.objects o ON s.object_id = o.object_id AND (index_id=0 or index_id=1)
GROUP BY o.Name
*2nd query should be more precise
Inner joining this queries to your dbo.[columns] can filter the results only for your desired tables.
Try this using CURSOR And Dynamic sql
CREATE TABLE #temp(count_ int,table_name varchar(50))
DECLARE #column_Name VARCHAR(50)
DECLARE #query VARCHAR(500)
DECLARE table_cursor CURSOR FOR
SELECT [column_name] from dbo.[column_name]
OPEN product_cursor
FETCH NEXT FROM product_cursor INTO #column_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query='INSERT INTO #temp SELECT'+ #column_Name+',COUNT(*) FROM'+ #column_Name
EXEC sp_executesql #SQLStatement=#query
/*this will insert the coresponding table name and its row count to #temp*/
END
CLOSE product_cursor
DEALLOCATE product_cursor
select * from #temp

TSQL: Using a Table in a Variable in a Function

I'm trying to do a select from a table that will need to be in a variable. I'm working with tables that are dynamically created from an application. The table will be named CMDB_CI_XXX, where XXX will be an integer value based on a value in another table. The ultimate goal is to get the CI Name from the table.
I've tried passing the pieces that make up the table name to a function and string them together and then return the name value, but I'm not allowed to use an EXEC statement in a function.
This is what I want to execute to get the name value back:
Select [Name] from 'CMDB_CI_' + C.CI_TYPE_ID + Where CI_ID = c.CI_ID
This is the code in the SP that I'd like to use the function in to get the name value:
SELECT
CI_ID,
C.CI_TYPE_ID,
CI_CUSTOM_ID,
STATUS,
CI_TYPE_NAME,
--(Select [Name] from CMDB_CI_ + C.CI_TYPE_ID + Where CI_ID = c.CI_ID)
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
join [footprints].[dbo].[CMDB50_CI_TYPE] t
on c.CI_TYPE_ID = t.CI_TYPE_ID
where status <> 'retired'
order by CI_TYPE_NAME
I'm not sure what to do with this. Please help?
Thanks,
Jennifer
-- This part would be a SP parameter I expect
DECLARE #tableName varchar(100)
SET #tableName = 'CMDB_CI_508'
-- Main SP code
DECLARE #sqlStm VARCHAR(MAX)
SET #sqlStm = 'SELECT *
FROM '+ #tableName
EXEC (#sqlStm)
Fiddle http://sqlfiddle.com/#!3/436a7/7
First off, yes, I know it's a bad design. I didn't design it. It came with the problem tracking software that my company bought for our call center. So I gave up altogether on the approach I was going for and used a cursor to pull all the the names from the various tables into one temp table and then used said temp table to join to the original query.
ALTER Proc [dbo].[CI_CurrentItems]
As
Declare #CIType nvarchar(6)
Declare #Qry nvarchar(100)
/*
Create Table Temp_CI
( T_CI_ID int,
T_CI_Type_ID int,
T_Name nvarchar(400)
)
*/
Truncate Table Temp_CI
Declare CI_Cursor Cursor For
select distinct CI_TYPE_ID FROM [footprints].[dbo].[CMDB50_CI_COMMON]
where STATUS <> 'Retired'
Open CI_Cursor
Fetch Next from CI_Cursor into #CIType
While ##FETCH_STATUS = 0
BEGIN
Set #Qry = 'Select CI_ID, CI_Type_ID, Name from Footprints.dbo.CMDB50_CI_' + #CIType
Insert into Temp_CI Exec (#Qry)
Fetch Next from CI_Cursor into #CIType
END
Close CI_Cursor
Deallocate CI_Cursor
SELECT CI_ID,
C.CI_TYPE_ID,
CI_CUSTOM_ID,
STATUS,
CI_TYPE_NAME,
T_Name
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
JOIN [footprints].[dbo].[CMDB50_CI_TYPE] t
ON c.CI_TYPE_ID = t.CI_TYPE_ID
JOIN Temp_CI tc
ON c.CI_ID = tc.T_CI_ID
AND t.CI_TYPE_ID = tc.T_CI_TYPE_ID
WHERE STATUS <> 'retired'
ORDER BY CI_TYPE_NAME

SQL while loop with Temp Table

I need to create a temporary table and then update the original table. Creating the temporary table is not a problem.
create table #mod_contact
(
id INT IDENTITY NOT NULL PRIMARY KEY,
SiteID INT,
Contact1 varchar(25)
)
INSERT INTO #mod_contact (SiteID, Contact1)
select r.id, r.Contact from dbo.table1 r where CID = 142
GO
Now I need to loop through the table and update r.contact = SiteID + r.contact
I have never used a while loop before and can't seem to make any examples I have seen work.
You can do this in multiple ways, but I think you're looking for a way using a cursor.
A cursor is sort of a pointer in a table, which when incremented points to the next record. ( it's more or less analogeous to a for-next loop )
to use a cursor you can do the following:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT id, siteId, contract FROM #mod_contract
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE dbo.table1
SET contract = #varSiteId + #varContract -- It might not work due to the different types
WHERE id = #varId
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
END
CLOSE CUR
DEALLOCATE CUR
It's not the most efficient way to get this done, but I think this is what you where looking for.
Hope it helps.
Use a set based approach - no need to loop (from the little details):
UPDATE
r
SET
r.Contact = m.SiteID + r.Contact
FROM
table1 r
INNER JOIN
#mod_contact m
ON m.id=r.id
Your brain wants to do this:
while records
update(i); //update record i
records = records + 1
end while
SQL is set based and allows you to take a whole bunch of records and update them in a single command. The beauty of this is you can use the WHERE clause to filter certain rows that are not needed.
As others have mentioned, learning how to do loops in SQL is generally a bad idea; however, since you're trying to understand how to do something, here's an example:
DECLARE #id int
SELECT #ID =1
WHILE #ID <= (SELECT MAX(ID) FROM table_1)
-- while some condition is true, then do the following
--actions between the BEGIN and END
BEGIN
UPDATE table_1
SET contact = CAST(siteID as varchar(100)) + contact
WHERE table_1.CID = #ID
--increment the step variable so that the condition will eventually be false
SET #ID = #ID + 1
END
--do something else once the condition is satisfied
PRINT 'DONE!! Don't try this in production code...'
Try this one:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT column1,column2 FROM table
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
--DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM Table2
WHERE column1 = #varId
AND column2 = #varSiteId
FETCH NEXT FROM CUR INTO #varId, #varSiteId
END
CLOSE CUR
DEALLOCATE CUR
need to create a temporary table and then up date the original table.
Why use a temporary table at all? Your CID column doesn't appear in the temporary table, so I don't see how you can successfully update the original table using SiteID, unless there is only one row where CID = 142 in which using a temp table is definitely overkill.
You can just do this:
UPDATE dbo.table1
SET contact = SiteID + contact
WHERE CID = 142;
Here's a related example which may help getting you to 'think in SQL':
UPDATE T
SET A = B, B = A;
Assuming A and B are of the same type, this would successfully swap their values.

Delete rows from multiple tables using a single query (SQL Express 2005) with a WHERE condition

This is the query I'm using:
DELETE TB1.*, TB2.*
FROM TB1
INNER JOIN TB2 ON TB1.PersonID = TB2.PersonID
WHERE (TB1.PersonID)='2'
It's working fine in MS Access but getting error (Incorrect syntax near ','.) in SQL Server Express 2005.
How to solve it? Please help.
You cannot DELETE from multiple tables with a single expression in SQL 2005 - or any other standard SQL for that matter. Access is the exception here.
The best method to get this effect is to specify FOREIGN KEYS between the table with an ON DELETE trigger.
Why you don't use a DELETE CASCADE FK ?
This cannot be done in one statement. You will have to use 2 statements
DELETE FROM TB1 WHERE PersonID = '2';
DELETE FROM TB2 WHERE PersonID = '2';
As i know, you can't do it in a sentence.
But you can build an stored procedure that do the deletes you want in whatever table in a transaction, what is almost the same.
I don't think you can delete from multiple tables at once (though I'm not certain).
It sounds to me, however, that you would be best to achieve this effect with a relationship that cascades deletes. If you did this you would be able to delete the record from one table and the records in the other would be automatically deleted.
As an example, say the two tables represent a customer, and the customer's orders. If you setup the relationship to cascade deletes, you could simply delete record in the customer table, and the orders would get deleted automatically.
See the MSDN doc on cascading referential integrity constraints.
Specify foreign key for the details tables which references to the primary key of master and set Delete rule = Cascade .
Now when u delete a record from the master table all other details table record based on the deleting rows primary key value, will be deleted automatically.
So in that case a single delete query of master table can delete master tables data as well as child tables data.
Use this in procedure
declare cu cursor for SELECT [name] FROM sys.Tables where [name] like 'tbl_%'
declare #table varchar(100)
declare #sql nvarchar(1000)
OPEN cu
FETCH NEXT FROM cu INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql = N'delete from ' + #table
EXEC sp_executesql #sql
FETCH NEXT FROM cu INTO #table
END
CLOSE cu;
DEALLOCATE cu;
I use this for cleaning up data in test/development databases. You can filter by table name and record count.
DECLARE #sqlCommand VARCHAR(3000);
DECLARE #tableList TABLE(Value NVARCHAR(128));
DECLARE #TableName VARCHAR(128);
DECLARE #RecordCount INT;
-- get a cursor with a list of table names and their record counts
DECLARE MyCursor CURSOR FAST_FORWARD
FOR SELECT t.name TableName,
i.rows Records
FROM sysobjects t,
sysindexes i
WHERE
t.xtype = 'U' -- only User tables
AND i.id = t.id
AND i.indid IN(0, 1) -- 0=Heap, 1=Clustered Index
AND i.rows < 10 -- Filter by number of records in the table
AND t.name LIKE 'Test_%'; -- Filter tables by name. You could also provide a list:
-- AND t.name IN ('MyTable1', 'MyTable2', 'MyTable3');
-- or a list of tables to exclude:
-- AND t.name NOT IN ('MySpecialTable', ... );
OPEN MyCursor;
FETCH NEXT FROM MyCursor INTO #TableName, #RecordCount;
-- for each table name in the cursor, delete all records from that table:
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'DELETE FROM ' + #TableName;
EXEC (#sqlCommand);
FETCH NEXT FROM MyCursor INTO #TableName, #RecordCount;
END;
CLOSE MyCursor;
DEALLOCATE MyCursor;
Reference info:
sysobjects
sysindexes
SQL Server Cursors
Generally I do deletions from multiple tables with one query.
It works correct with PostgreSQL, but doesn't work for MSSQL, and that's why I got here.
With Postgres (I don't know about other DBs) you can do:
WITH obsolete_ids AS (
SELECT pr_r."ID" AS ids
FROM "PULL_REQUEST" pr_r
WHERE 1=1
AND pr_r."STATUS" IN (1)
) , del_commit_junc AS (
DELETE
FROM "PR_TO_COMMIT"
WHERE "REQUEST_ID" IN (SELECT ids FROM obsolete_ids)
)
DELETE
FROM "PULL_REQUEST" pr_out
WHERE pr_out ."ID" IN (SELECT ids FROM obsolete_ids)
Actually In my original Query I delete foreign keys from 2 more tables, but here I just paste an example.
That way I solved problem with Foreign Keys in "PR_TO_COMMIT" table.
The way I am using to Delete rows from multiple tables in SQL Server?
The most important is to use on delete cascade when creating a foreign key in the table
#Table 1 Create:#
create table Customer_tbl
(
C_id int primary key,
C_Name varchar(50),
C_Address varchar(max),
City varchar(50)
);
#Table 2: Create with Foreign Key Constraints#
create table [order]
(
Ord_Id int primary key,
Item varchar(50),
Quantity int,
Price_Of_1 int,
C_id int foreign key references Customer_tbl(C_id)
on delete cascade
);
delete from Customer_tbl where C_id = 2;
You can use something like the following:
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name IN ("TB2","TB1") -- use these databases
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
DELETE FROM #name WHERE PersonID ='2'
FETCH NEXT FROM db_cursor INTO #name
END
CREATE PROCEDURE sp_deleteUserDetails
#Email varchar(255)
AS
declare #tempRegId as int
Delete UserRegistration where Email=#Email
set #tempRegId = (select Id from UserRegistration where Email = #Email)
Delete UserProfile where RegID=#tempRegId
RETURN 0
Try this query
DELETE TB1, TB2 FROM TB1 INNER JOIN TB2
WHERE TB1.PersonID = TB2.PersonID and TB1.PersonID = '2'
$qry = "DELETE lg., l. FROM lessons_game lg RIGHT JOIN lessons l ON lg.lesson_id = l.id WHERE l.id = ?";
lessons is Main table and
lessons_game is subtable so Right Join
DELETE TB1, TB2
FROM customer_details
LEFT JOIN customer_booking on TB1.cust_id = TB2.fk_cust_id
WHERE TB1.cust_id = $id