Count columns of a result from with block? - sql-server

I am exploring provided code. I have various CTEs, and I want to count the columns in each CTE? Or select the differences in columns per CTE?
The below code will grab the count from a table in the DB, but I'm not sure how to apply this to CTEs?
select count(*)
from INFORMATION_SCHEMA.columns
where TABLE_CATALOG = 'db_name'
and TABLE_NAME = 'table_name'

First Create CTE and then insert just one record into temp table , then query the sys.columns table to get the list of the columns in CTE
IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
DROP TABLE #temp;
go
With CTE1 as (select * from table_name)
select top 1 * into #temp from CTE1
SELECT count(*) FROM tempdb.sys.columns where object_id = object_id('tempdb..#temp')

Related

Creating a Query for each row in a SQL Table

I have a schema in my SQL table out of which some table has a time value stamp (same column name 'timestamp' in all the tables in the schema) and I need to create a new table which will give the latest time stamp for each such table. I have achieved a part which will give me a table with 2 columns, one the table name column and another column which gives the query for each table which if runs will give me the latest timeStamp for each table in table name Column. The script I used is as follows and I show 3 rows as an example:
WITH CTE AS
(
SELECT
CONCAT(schema_name(t.schema_id), '.',t.name) AS table_name,
c.name AS 'time_stamp'
FROM
sys.tables t
INNER JOIN
sys.columns c ON c.object_id = t.object_id
WHERE
schema_name(t.schema_id) = 'PROD'
AND c.name = 'timestamp'
)
SELECT table_name, time_stamp
INTO #TEMP_TABLE
FROM CTE
DECLARE #i int = 1, #c int = (SELECT COUNT(*) FROM #TEMP_TABLE)
DECLARE #Result TABLE
(
tName varchar(500),
tStamp varchar(500)
)
WHILE (#i <= #c)
BEGIN
INSERT INTO #Result
SELECT
table_name,
'SELECT MAX('+ time_stamp +') FROM ' + table_name
FROM #TEMP_TABLE;
SET #i = #i + 1
END
DROP TABLE #TEMP_TABLE
SELECT * FROM #RESULT
When I run this script I get the following table (3 rows shown as an illustration)
My output (O)
tName tStamp
-----------------------------------------------------------
PROD.table_A SELECT MAX(time_stamp) FROM PROD.table_A
PROD.table_B SELECT MAX(time_stamp) FROM PROD.table_B
PROD.table_C SELECT MAX(time_stamp) FROM PROD.table_C
However what I want is the value of the query in the tStamp column and not the query string. So actually the output table should look like (say assuming the query in each of the above rows in column tStamp. I put in some max values as an example when we run each query in tStamp column)
My final expected output (F)
tName tStamp
------------------------------------------
PROD.table_A 2021-10-12 14:20:56.000
PROD.table_B 2021-11-01 19:04:35.000
PROD.table_C 2021-10-23 08:07:12.000
I am in a limbo at this stage not sure, how to get the table F from table O. So I will really appreciate any help. If it can be possible to tweak something which I am doing to get directly the output table F or if we can work on the table O to get to table F anything can help.
Thanks in advance.
If this is a one shot thing, I would consider just using a macro (vim, excel) to generate the query text for each table using your CTE results and then paste it back in and run.
If not, you could consider some of the suggestions for dynamic sql in this article: [https://www.mssqltips.com/sqlservertip/1160/execute-dynamic-sql-commands-in-sql-server/][1]

Simple query gone wrong

I must be having an off day. This should be obvious but I don't get it.
-- check for necessary updates to dbnotes
select count(distinct table_name)
from ccsv4.[INFORMATION_SCHEMA].[COLUMNS]
returns 46
select count(distinct table_name)
from dbnotes
returns 44
select distinct table_name
from ccsv4.[INFORMATION_SCHEMA].[COLUMNS]
where table_name not in (select distinct table_name from dbnotes)
order by table_name
returns nothing
select distinct table_name
from dbnotes
where table_name not in (select distinct table_name
from ccsv4.[INFORMATION_SCHEMA].[COLUMNS])
order by table_name
returns nothing
What am I missing guys?
You are using not in. If any value from the subquery is NULL, nothing will be returned.
With a subquery, always use not exists. It has the right semantics:
select distinct table_name
from ccsv4.[INFORMATION_SCHEMA].[COLUMNS] c
where not exists (select 1
from dbnotes d
where d.table_name = c.table_name
);
I am pretty sure that tables have to have at least one column, so you might as well use information_schema.tables instead. It saves you the distinct:
select table_name
from ccsv4.information_schema.tables t
where not exists (select 1
from dbnotes d
where d.table_name = t.table_name
);

How can I delete the duplicate rows while keeping the original record?

I have an one table as below a picture which indicates some duplicated rows.I can find the duplicated rows but I could not able to delete it because of there is no any unique ID that I can distinguish. There were lots of duplicated rows like that in same table I just screenshot a piece of that.
As a result,according to the below picture, how can I delete the duplicated rows but keep original ?
One solution you could consider is copying all unique records into a temporary table, thus removing the duplicates. You could then truncate the original table and re-populate it from the temporary table you've created. The code would be something like this:
SELECT DISTINCT * INTO #tempTable FROM MyTable
TRUNCATE TABLE MyTable;
INSERT INTO MyTable (LocationID, UnitID, CameraID ... IsActiveHours)
SELECT LocationID, UnitID, CameraID ... IsActiveHours FROM #tempTable;
This isn't always an option due to key constraints and amount of data, but useful in certain cases. Take it as you may.
You could use a cte and Row_Number() to accomplish this. If you are satisfied with the results, remove the final select and un-comment the delete statement
;with cte as (
Select *,RowNr=Row_Number() over (Partition By LocationId Order by Date_T)
From YourTable
)
Select * from cte Where RowNr>1
-- Delete From cte Where RowNr>1
You would be best adding an identity column to make things easier however this can be done without a TRUNCATE using the following:
--GET DUPLICATE ROWS INTO A TEMP TABLE (YOU MAY NOT NEED TO USE ALL THE COLUMNS TO IDENTIFY A DUPLICATE)
SELECT ROW_NUMBER() OVER (ORDER BY ColA) AS RowNo, ColA, ColB, ColC, COUNT(*) As [Count]
INTO #TEMP1
FROM test
GROUP BY ColA, ColB, ColC
HAVING COUNT(*) > 1
--LOOP THROUGH DUPLICATES
DECLARE #RowNo INT
DECLARE #Duplicates INT
SET #RowNo = 1
WHILE EXISTS(SELECT * FROM #TEMP1)
BEGIN
--GET A COUNT OF ADDITIONAL ROWS FOR THIS DUPLICATE
SET #Duplicates = (SELECT [Count] FROM #TEMP1 WHERE RowNo = #RowNo) - 1
--DELETE THE ROWS WE DONT NEED
DELETE TOP (#Duplicates) t1
FROM test t1
JOIN #TEMP1 t2 ON t1.ColA = t2.ColA AND t1.ColB = t2.ColB AND t1.ColC = t2.ColC
WHERE t2.RowNo = #RowNo
--REMOVE THE ROW FROM THE TEMP TABLE
DELETE FROM #TEMP1 WHERE RowNo = #RowNo
--INCREASE THE ROW NO TO MOVE TO THE NEXT ROW
SET #RowNo = #RowNo + 1
END
--DROP THE TEMP TABLE
DROP TABLE #TEMP1
This is the query that fix this issue.
WITH X AS (
SELECT ROW_NUMBER() OVER(PARTITION BY LocationId,date_t ORDER BY LocationId desc) as 'rownum',LocationId,
date_T AS T
FROM Counts
)
--SELECT * FROM X WHERE rownum >1
DELETE FROM X
WHERE rownum <> 1

Select particular columns and insert in another table

My tables are defined like below:
#TempData(ColmnA, ColumnB) -- Temp table.
EmployeeDSU(ColumnA, ColumnB, ColumnC, ColumnD, ColumnE)
#TempData is coming from .csv file and columns may change.
Now, what I want to do is:
If ColumnA, ColumnB exists in EmployeesDSU table, then the #TempData data should be inserted into EmployeesDSU table, and for all the remaining columns in EmployeesDSU table, NULL should be inserted. I should do this everything in Stored procedure.
Can anybody please suggest me how to do!
if object_id('tempdb..#TempData') is not null drop table #TempData;
select 1 ColumnA, 1 ColumnB into #TempData;
if not exists(
select
*
from
(
select
c.name
from
tempdb.sys.columns c
where
c.object_id = object_id('tempdb..#TempData')
) a
left join (
select
*
from
sys.columns c
where
c.object_id = object_id('dbo.EmployeeDSU')
) b on a.name = b.name
where
b.name is null
) begin
insert into dbo.EmployeeDSU(ColumnA, ColumnB)
select
t.ColumnA, t.ColumnB
from
#TempData t
;
end;

Is there a way to get the fields names of a table created in a function / stored procedure?

when I need the columns of an existing table I use the query:
SELECT c.[name]
FROM
(SELECT * from syscolumns) c
INNER JOIN
(SELECT [id] from sysobjects where name= 'tableName') o on c.[id]=o.[id]
I need the fields of a table that I create during runTime:
select
a.ID,
b.lName,
b.fName
into #T
from
a
inner join
b on a.id=b.id
.
select * from #T_columns
will result a table with 3 rows:
id
lName
fName
How can I do it?
Thanks
When you create a temp table, it will be in tempdb. You can look it up like this:
SELECT COLUMN_NAME
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME LIKE '#T|_%' ESCAPE '|'
If you do a SELECT * FROM INFORMATION_SCHEMA.TABLES in tempdb, you'll see the temp table name you use (#T) actually has a number of underscores appended to it followed by a unique identifier. So you won't find it it you just search where table_name = '#T'.
So that's why you have to use a LIKE as I've shown above. This will match on "#T_" followed by any other other characters.
Try this
SELECT sc.NAME
FROM
tempdb..SYSOBJECTS so JOIN
tempdb..SYSCOLUMNS sc ON sc.id = so.id
WHERE so.NAME LIKE '#T%'

Resources