Flatten recursive data - tsql

I have a table glclassifications (Exact software) that looks like this:
CREATE TABLE [glclassifications](
[ID] [nvarchar](500) NULL, --(contains uniqueidentifier)
[Code] [nvarchar](500) NULL,
[Description] [nvarchar](500) NULL,
[Parent] [nvarchar](500) NULL --(contains uniqueidentifier)
)
It holds classifications that are hierarchical (hence the Parent column that refers to the ID of another record.)
I need this table to be 'flattened' so that I have
Parent_ID,
Parent_code,
Parent_description,
--child1
Child1_ID,
Child1_code,
Child1_description,
--child2
Child2_ID....
-- up until including child9
and so on.
My predecessor left me with this query that violates a lot of the designprinciples that we agreed upon. One of those is not using (temp)tables. I would like to simplify this script and preferably get the output as a view and not as a table. A catch is that the resulting view needs to deliver columns for 8 children, even if there are less in the table...
/* drop duplicates in glclassifications */
WITH CTE AS (
SELECT ROW_NUMBER() OVER (
PARTITION BY ID
ORDER BY ( SELECT 0)
) RN
FROM [dbo].[glclassifications]
)
DELETE FROM CTE
WHERE RN > 1;
/* drop tmp table */
DROP TABLE IF EXISTS #H;
CREATE TABLE #H (
Code varchar(100),
Description varchar(250),
ID varchar(100),
Division int
)
/* declare table */
DECLARE #n INT = 1
DECLARE #Sql varchar(50)
WHILE #n < 10 BEGIN
DECLARE #col_name varchar(10) = CONCAT('Code_' , #n)
SET #Sql = 'ALTER TABLE #H ADD ' + QUOTENAME(#col_name) + ' varchar(20) NULL'
EXEC (#Sql)
SET #col_name = CONCAT('Name_' , #n)
SET #Sql = 'ALTER TABLE #H ADD ' + QUOTENAME(#col_name) + ' varchar(250) NULL'
EXEC (#Sql)
SET #n = #n + 1
END
/* insert level 1 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1)
SELECT
Code,Description,ID,bip_office,Code,Description
FROM
[dbo].[glclassifications]
WHERE Parent = ''
/* insert level 2 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2)
SELECT
e.Code,e.Description,e.Id,e.bip_office,Code_1,Name_1,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL ;
/* insert level 3 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2,Code_3, Name_3)
SELECT
e.Code,e.Description,e.Id,e.bip_office, Code_1,Name_1,Code_2, Name_2,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL ;
/* insert level 4 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2,Code_3, Name_3, Code_4, Name_4)
SELECT
e.Code,e.Description,e.Id,e.bip_office, Code_1,Name_1,Code_2, Name_2,Code_3, Name_3,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL ;
/* insert level 5 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2,Code_3, Name_3, Code_4, Name_4, Code_5, Name_5)
SELECT
e.Code,e.Description,e.Id,e.bip_office,Code_1,Name_1,Code_2, Name_2,Code_3, Name_3,Code_4, Name_4,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL ;
/* insert level 6 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2,Code_3, Name_3, Code_4, Name_4, Code_5, Name_5,Code_6, Name_6)
SELECT
e.Code,e.Description,e.Id,e.bip_office,Code_1,Name_1,Code_2, Name_2,Code_3, Name_3,Code_4, Name_4,Code_5, Name_5,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL ;
/* insert level 7 */
INSERT INTO #H (Code,[Description],ID,Division,Code_1, Name_1, Code_2, Name_2,Code_3, Name_3, Code_4, Name_4, Code_5, Name_5,Code_6, Name_6,Code_7, Name_8)
SELECT
e.Code,e.Description,e.Id,e.bip_office,Code_1,Name_1,Code_2, Name_2,Code_3, Name_3,Code_4, Name_4,Code_5, Name_5,Code_6, Name_6,e.Code,e.Description
FROM
[dbo].[glclassifications] e
JOIN #H h on h.ID = e.Parent
WHERE e.ID not in (SELECT DISTINCT ID from #H ) AND Parent IS NOT NULL;
/* store to table */
DROP TABLE IF EXISTS [dbo].[gb-hierarchie];
SELECT hie.*
INTO [dbo].[gb-hierarchie]
FROM #H hie
I did this
WITH cte_org AS (
SELECT
ID,
Code,
Description,
Parent
FROM
[dbo].[glclassifications]
WHERE len(parent) = 0
UNION ALL
SELECT
e.ID,
e.Code,
e.Description,
e.parent
FROM
[dbo].[glclassifications] e
INNER JOIN cte_org o
ON o.ID = e.parent
)
SELECT * FROM cte_org;
but how to continue?

With thanks to Bill Jetzer: simply joining the tables on itself 8 times was the easiest way to get these results

Related

Issue with PK violation on insert

I have a scenario where almost all of the tables have issues with the PK value as follows. This results is a database error or the violation of the PK insert.
When using the DBCC CheckIdent it displays an inconsistency between the next value and the current one.
Can anyone have a reason for the mismatch happening on several tables?
Since this database is then replicate, I'm afraid this error will propagate across the environment.
I adapted this script to fix it, but really trying to figure out the root of the problem.
/** Version 3.0 **/
if object_id('tempdb..#temp') is not null
drop table #temp
;
with cte as (
SELECT
distinct
A.TABLE_CATALOG AS CATALOG,
A.TABLE_SCHEMA AS "SCHEMA",
A.TABLE_NAME AS "TABLE",
B.COLUMN_NAME AS "COLUMN",
IDENT_SEED (A.TABLE_NAME) AS Seed,
IDENT_INCR (A.TABLE_NAME) AS Increment,
IDENT_CURRENT (A.TABLE_NAME) AS Curr_Value
, DBPS.row_count AS NumberOfRows
FROM INFORMATION_SCHEMA.TABLES A
inner join INFORMATION_SCHEMA.COLUMNS B on b.TABLE_NAME = a.TABLE_NAME and b.TABLE_SCHEMA = a.TABLE_SCHEMA
inner join sys.identity_columns IC on OBJECT_NAME (IC.object_id) = a.TABLE_NAME
inner join sys.dm_db_partition_stats DBPS ON DBPS.object_id =IC.object_id
inner join sys.indexes as IDX ON DBPS.index_id =IDX.index_id
WHERE A.TABLE_CATALOG = B.TABLE_CATALOG AND
A.TABLE_SCHEMA = B.TABLE_SCHEMA AND
A.TABLE_NAME = B.TABLE_NAME AND
COLUMNPROPERTY (OBJECT_ID (B.TABLE_NAME), B.COLUMN_NAME, 'IsIdentity') = 1 AND
OBJECTPROPERTY (OBJECT_ID (A.TABLE_NAME), 'TableHasIdentity') = 1 AND
A.TABLE_TYPE = 'BASE TABLE'
)
select 'DBCC CHECKIDENT ('''+A.[SCHEMA]+'.'+a.[TABLE]+''', reseed)' command
, ROW_NUMBER() OVER(ORDER BY a.[SCHEMA], a.[TABLE] asc) AS ID
, A.Curr_Value
, a.[TABLE]
into #temp
from cte A
ORDER BY A.[SCHEMA], A.[TABLE]
declare #i int = 1, #count int = (select max(ID) from #temp)
declare #text varchar(max) = ''
select #COUNT= count(1) FROM #temp
WHILE #I <= #COUNT
BEGIN
SET #text = (SELECT command from #temp where ID=#I)
EXEC (#text + ';')
print #text
select Curr_Value OldValue, ident_current([TABLE]) FixValue, [TABLE] from #temp where ID=#I
SET #I = #I + 1
SET #text='';
END
go
maybe someone or something with enough permissions made a mistake by reseeding?
As simple as this:
create table testid (
id int not null identity (1,1) primary key,
data varchar (3)
)
insert into testid (data) values ('abc'),('cde')
DBCC CHECKIDENT ('testid', RESEED, 1)
insert into testid (data) values ('bad')

WHERE in NOT EXISTS clause being ignored

I'm trying to fill a table with rows that should be there: If a city in #Maps does not exist in #Results, then I will fill it using NOT EXISTS. The issue is that the filterisused = 1 not only is ignored, it seems to void the NOT EXISTS.
With IsUsed = 1, everything in #Maps will be inserted to #Results regardless if it exists or not.
If I remove IsUsed = 1, both rows from NY are inserted (correct behavior but not what I'm looking for).
Here's the code:
declare #Maps table
(
Name varchar(20),
IsUsed bit,
Code varchar(20)
)
insert into #Maps
select 'NY', 1, 'NY1'
union select 'NY', 0, 'NY2'
union select 'FL', 0, 'FL1'
union select 'TX', 0, 'TX1'
declare #Results table
(
Name varchar(20),
Value int,
Code varchar(20)
)
insert into #results
select 'FL', 12, 'FL1'
union
select 'TX', 54,'TX1'
union
select 'CA', 54,'CA1'
union
select 'NJ', 54,'NJ1'
insert into #results
select Name, 999, code from #Maps m
-- This adds everything even if it exists
where not exists (select name from #Results p where p.name = m.name and IsUsed = 1)
-- This adds both 'NY'. Partially correct but adds column IsUsed = 0
-- where not exists (select name from #Results p where p.name = m.name)
select * from #results
How can I add the one row that's not included in #results and has IsUsed equal to 1? In this case it would be {'NY', 1, 'NY1}`.
I understand that there are many ways of accomplishing this, but I'm interested in knowing how the where clause in not exists work.
You have to remove the IsUsed=1 from the NOT EXISTS and add it to the WHERE:
insert into #results
select Name, 999, code
from #Maps m
where m.IsUsed = 1
and not exists (select name from #Results p where p.name = m.name)
I think you confuse how an insert select works. The select is run independently. The insert is not committed until the end of the statement. See all the inserted cnt is 4.
declare #maps table(name varchar(10), isUsed bit, code varchar(10));
insert into #Maps values
('NY', 1, 'NY1')
, ('NY', 0, 'NY2')
, ('FL', 0, 'FL1')
, ('TX', 0, 'TX1')
declare #Results table (Name varchar(20), Value int, Code varchar(20), cnt int)
insert into #results values
('FL', 12, 'FL1', null)
, ('TX', 54, 'TX1', null)
, ('CA', 54, 'CA1', null)
, ('NJ', 54, 'NJ1', null)
select * from #results;
insert into #Results
select m.Name, 999, m.code
, (select count(*) from #results) as cnt
from #Maps m
where not exists (select name
from #Results p
where p.name = m.name
and m.IsUsed = 1)
select * from #results;
On the first NY where p.name = m.name is false so not exits is true
On the second NY where p.name = m.name is false so not exits is true
The first NY as not been committed
On the FL and TL the where p.name = m.name is true but m.IsUsed = 1 is false so not exits is true

I am getting Dollar sign unterminated

I want to create a function like below which inserts data as per the input given. But I keep on getting an error about undetermined dollar sign.
CREATE OR REPLACE FUNCTION test_generate
(
ref REFCURSOR,
_id INTEGER
)
RETURNS refcursor AS $$
DECLARE
BEGIN
DROP TABLE IF EXISTS test_1;
CREATE TEMP TABLE test_1
(
id int,
request_id int,
code text
);
IF _id IS NULL THEN
INSERT INTO test_1
SELECT
rd.id,
r.id,
rd.code
FROM
test_2 r
INNER JOIN
raw_table rd
ON
rd.test_2_id = r.id
LEFT JOIN
observe_test o
ON
o.raw_table_id = rd.id
WHERE o.id IS NULL
AND COALESCE(rd.processed, 0) = 0;
ELSE
INSERT INTO test_1
SELECT
rd.id,
r.id,
rd.code
FROM
test_2 r
INNER JOIN
raw_table rd
ON rd.test_2_id = r.id
WHERE r.id = _id;
END IF;
DROP TABLE IF EXISTS tmp_test_2_error;
CREATE TEMP TABLE tmp_test_2_error
(
raw_table_id int,
test_2_id int,
error text,
record_num int
);
INSERT INTO tmp_test_2_error
(
raw_table_id,
test_2_id,
error,
record_num
)
SELECT DISTINCT
test_1.id,
test_1.test_2_id,
'Error found ' || test_1.code,
0
FROM
test_1
WHERE 1 = 1
AND data_origin.id IS NULL;
INSERT INTO tmp_test_2_error
SELECT DISTINCT
test_1.id,
test_1.test_2_id,
'Error found ' || test_1.code,
0
FROM
test_1
INNER JOIN
data_origin
ON
data_origin.code = test_1.code
WHERE dop.id IS NULL;
DROP table IF EXISTS test_latest;
CREATE TEMP TABLE test_latest AS SELECT * FROM observe_test WHERE 1 = 2;
INSERT INTO test_latest
(
raw_table_id,
series_id,
timestamp
)
SELECT
test_1.id,
ds.id AS series_id,
now()
FROM
test_1
INNER JOIN data_origin ON data_origin.code = test_1.code
LEFT JOIN
observe_test o ON o.raw_table_id = test_1.id
WHERE o.id IS NULL;
CREATE TABLE latest_observe_test as Select * from test_latest where 1=0;
INSERT INTO latest_observe_test
(
raw_table_id,
series_id,
timestamp,
time
)
SELECT
t.id,
ds.id AS series_id,
now(),
t.time
FROM
test_latest t
WHERE t.series_id IS DISTINCT FROM observe_test.series_id;
DELETE FROM test_2_error re
USING t
WHERE t.test_2_id = re.test_2_id;
INSERT INTO test_2_error (test_2_id, error, record_num)
SELECT DISTINCT test_2_id, error, record_num FROM tmp_test_2_error ORDER BY error;
UPDATE raw_table AS rd1
SET processed = case WHEN tre.raw_table_id IS null THEN 2 ELSE 1 END
FROM test_1 tr
LEFT JOIN
tmp_test_2_error tre ON tre.raw_table_id = tr.id
WHERE rd1.id = tr.id;
OPEN ref FOR
SELECT 1;
RETURN ref;
OPEN ref for
SELECT o.* from observe_test o
;
RETURN ref;
OPEN ref FOR
SELECT
rd.id,
ds.id AS series_id,
now() AS timestamp,
rd.time
FROM test_2 r
INNER JOIN raw_table rd ON rd.test_2_id = r.id
INNER JOIN data_origin ON data_origin.code = rd.code
WHERE o.id IS NULL AND r.id = _id;
RETURN ref;
END;
$$ LANGUAGE plpgsql VOLATILE COST 100;
I am not able to run this procedure.
Can you please help me where I have done wrong?
I am using squirrel and face the same question as you.
until I found that:
-- Note that if you want to create the function under Squirrel SQL,
-- you must go to Sessions->Session Properties
-- then SQL tab and change the Statement Separator from ';' to something else
-- (for intance //). Otherwise Squirrel SQL sends one piece to the server
-- that stops at the first encountered ';', and the server cannot make
-- sense of it. With the separator changed as suggested, you type everything
-- as above and end with
-- ...
-- end;
-- $$ language plpgsql
-- //
--
-- You can then restore the default separator, or use the new one for
-- all queries ...
--

How can I use sp_spaceused on specific tables?

I'm trying to call sp_spaceused to get the number of rows in a few specific tables that I want to monitor, but I'm trying to avoid using a cursor.
I've made a table to hold all the tables I want to monitor:
CREATE TABLE MonitoredTable
(
MonitoredTableID INT PRIMARY KEY IDENTITY(1, 1) NOT NULL
, DatabaseName NVARCHAR(128) NOT NULL
, SchemaName NVARCHAR(128) NOT NULL
, TableName NVARCHAR(128) NOT NULL
, RowNumberThreshold INT NOT NULL
, IsActive BIT NOT NULL
)
My problem is: I want to create a function that will only return MonitoredTableIDs for tables that their row counts exceed the defined RowNumberThreshold.
Here's what I'd like to do, but this is invalid SQL:
CREATE FUNCTION dbo.GetTablesLargerThanThreshold()
RETURNS #tablesLargerThanThreshold TABLE
(
MonitoredTableID INT NOT NULL
)
AS
BEGIN
INSERT INTO #tablesLargerThanThreshold
SELECT MonitoredTableID
FROM MonitoredTable
WHERE IsActive = 1
AND (SELECT [rows] FROM (EXEC sp_spaceused DatabaseName + '.' + SchemaName + '.' + TableName)) > RowNumberThreshold
RETURN
END
Is there a way I can check if the number of rows in a MonitoredTable are greater than the defined RowNumberThreshold without resorting to a cursor?
Something like this?
-- See the following pages for documentation on the tables used in this query:
--
-- sys.indexes https://msdn.microsoft.com/en-us/library/ms173760.aspx
-- sys.partitions https://msdn.microsoft.com/en-us/library/ms175012.aspx
-- sys.allocation_units https://msdn.microsoft.com/en-us/library/ms189792.aspx
-- sys.tables Only columns inherited from sys.object, see link below
-- sys.object https://msdn.microsoft.com/en-us/library/ms190324.aspx
SELECT OBJECT_NAME(i.OBJECT_ID) AS [TableName]
, p.[rows] AS [Num_Rows]
FROM sys.indexes AS i
INNER JOIN sys.partitions AS p
ON p.OBJECT_ID = i.OBJECT_ID
AND p.index_id = i.index_id
INNER JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
INNER JOIN sys.tables AS t
ON i.OBJECT_ID = t.OBJECT_ID
WHERE i.type <= 1 -- Heap or clustered index
AND a.type = 1 -- In-row data
AND t.type = 'U' -- User-defined table
AND t.is_ms_shipped = 0 -- sys.object was not created by an internal SQL Server component

Exlude row with same key from 1st select if exists in 2nd select statement in UNION

I have two tables Part and Service Entry Part. The first statement returns all parts and the second statement returns parts with a service type of 13.
What I need to do is if the second select returns a part then the record from second select should be inlcuded and that part from the first select should be be excluded
DECLARE #run_log TABLE(
[Instrument] nvarchar(max),
[SubSystem] NVARCHAR(max),
[AbPartNumber] NVARCHAR(max),
[RSLMSPartID] int,
[PartDescriptionWithParent] NVARCHAR(max),
[PartRevisionNumber] NVARCHAR(max),
[ServiceEntryID] int,
[Date] datetime,
[TSBNumber] nvarchar (max),
[CRNumber] nvarchar(max)
)
insert #run_log
-- parts with default revision number
select
System.SystemFullName as Instrument,
Part.System as SubSystem,
Part.AbPartNo as AbPartNumber,
Part.ID as RSLMSPartID,
Part.PartDescriptionWithParent,
Part.RevisionNumber as PartRevisionNumber,
NULL as ServiceEntryID,
NULL as Date,
NULL as TSBNumber,
NULL as CRNumber
from Part
inner join InstrumentType on Part.InstrumentTypeID = InstrumentType.ID
inner join SystemModule on SystemModule.InstrumentTypeID = Part.InstrumentTypeID
inner join System on System.ID = SystemModule.SystemID
WHERE ((#PlatformID =0) OR (System.PlatformID = #PlatformID) OR (#PlatformID = 12 AND System.PlatformID <= 2))
AND (#SelectedSystemID is null OR System.ID IN(select * from dbo.SplitInts_RBAR_1(#SelectedSystemID, ',')))
AND (#SelectedAbIDs is null OR Part.ID IN (select * from dbo.SplitInts_RBAR_1(#SelectedAbIDs,',')))
AND (#SelectedSubSystems is null OR Part.System IN (select * from dbo.SplitStrings_Moden(#SelectedSubSystems,',')))
AND System.Active = 1 and Part.Active = 1
ORDER BY SubSystem,RSLMSPartID
;WITH RunLogs AS(
SELECT *
FROM #run_log r
)
select * from RunLogs
UNION
select System.SystemFullName as Instrument,
Part.System as Subsystem,
Part.AbbottPartNo as AbPartNumber,
Part.ID as RSLMSPartID,
Part.PartDescriptionWithParent,
ServiceEntryPart.PartRevisionNumber AS PartRevisionNumber,
ServiceEntryPart.ServiceEntryID,
ServiceEntry.ServiceDateTime as Date,
ServiceEntry.TSBNumber,
ServiceEntry.CRNumber
from Part
inner join ServiceEntryPart on ServiceEntryPart.PartID = Part.ID
inner join ServiceEntry on ServiceEntry.ID = ServiceEntryPart.ServiceEntryID
inner join systemmodule on ServiceEntryPart.SystemModuleID = SystemModule.ID
inner join System on System.ID = SystemModule.SystemID
cross apply
dbo.SplitStrings_Moden(ServiceEntryPart.ServiceTypeIDs, N',') M2
JOIN dbo.SplitStrings_Moden('13', N',') P ON (M2.Item = P.Item)
WHERE System.Active = 1 AND Part.Active = 1
AND (#SelectedSystemID is null OR System.ID IN(select * from dbo.SplitInts_RBAR_1(#SelectedSystemID, ',')))
AND ((#PlatformID =0) OR (System.PlatformID = #PlatformID) OR (#PlatformID = 12 AND System.PlatformID <= 2))
AND (ServiceEntry.ServiceDateTime between #StartDate and #EndDate)
AND (#SelectedAbIDs is null OR Part.ID in (select * from dbo.SplitInts_RBAR_1(#SelectedAbIDs,',')))
AND (#SelectedSubSystems is null OR Part.System IN (select * from dbo.SplitStrings_Moden(#SelectedSubSystems,',')))