SQL Server - how to select while skipping other data - sql

I have data with following data
In this round 1 and 2 is related with course 231 and 776.
But I need to select output as
means if round 1 selected with field 231, it must skip other row of round with 1 and also skip the row with field with 231.
But round 3 and 4 has single record, then it should be included in output.
How can I achieve this result?
thanks
EDIT:
in case of round 3 has multiple record, then it table would be like:
and needed output is:

I wouldn't prefer to use cursor but for this situation, I couldn't provide a single query to retrieve desired output. So, you can try like this;
declare #round int
declare #field int
declare #selectedFields table (field int)
declare #expectedRounds table (Round int, field int)
DECLARE db_cursor CURSOR FOR
select * from (
select Round,min(Field) as Field from SampleTable group by Round having count(*) > 1) Records order by Round
insert into #expectedRounds
select Round,max(field) from SampleTable group by Round having count(*) = 1
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #round, #field
WHILE ##FETCH_STATUS = 0
BEGIN
declare #selectedField int
declare #selectedRound int
select top 1 #selectedRound = Round, #selectedField = field from SampleTable where Round = #round and field not in (select field from #selectedFields) order by Field asc
insert into #expectedRounds (Round, field) VALUES (#selectedRound, #selectedField)
insert into #selectedFields (field) VALUES (#selectedField)
FETCH NEXT FROM db_cursor INTO #round, #field
END
CLOSE db_cursor
DEALLOCATE db_cursor
select * from #expectedRounds order by Round asc

You could use something like this:
SELECT [year]
,[round]
,MIN([field])
FROM TABLE
GROUP BY [year]
,[round]
ORDER BY [year]
,[round]

Related

Convert Excel formula ' =COUNTIF($B$2:B2,[#[reg_no]]) ' to SQL

My excel sheet having a column Count is responsible for counting how many times one registration number is repeated as you can see in the given picture.
Whenever I am going to add any new record in my excel table this column go up and count how many records are there as like my reg_no
Let us take Example:
If we add new record at 17th id with
Reg_no = 3591
Name = 'dani'
grade = 'A'
Count ?
Now it will be like Count = 4
I want to convert this table into a SQL query and I am having a problem converting this Count column that how I am going to calculate this count column in SQL
Does anyone know? please help
step 1 create a temp table with empty column
SELECT * , null as desired_column ,
into #yourTable_t1
FROM #yourTable j;
step 2 create a cursor to calculate your desired_column and update temp_table
begin
declare #row int, #order int, #prod varchar(100), #prod_count int =0 ;
declare prod_cur cursor for
SELECT row_num, MyColumn1,MyColumn2
FROM #yourTable_t1 ;
open prod_cur;
fetch next from prod_cur into #row , #order, #prod;
while (##FETCH_STATUS=0)
begin
set #prod_count= ( select count(MyColumn2) from #yourTable_t1 where
MyColumn2= #prod and ROW_NUM <= #row);
update #yourTable_t1
set desired_column = #prod_count
where ROW_NUM= #row;
fetch next from prod_cur into #row , #order, #prod;
end;
close prod_cur;
deallocate prod_cur;
--select * from #yourTable_t1 order by MyColumn2;
end;
Good Luck!
This can be done using window functions
count(*) over (partition by rege_no order by id) as count
Online example

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;

Generating dummy data from existing data set is slow using cursor

I'm trying to generate dummy data from the existing data I have in the tables. All I want is to increase the number of records in Table1 to N specified amount. The other tables should increase based on the foreign key references.
The tables has one to many relationship. For one record in table 1, I can have multiple entries in table 2, and in table 3 I can have many records based on IDs of the second table.
Since IDs are primary keys, I either capture it by
SET #NEWLY_INSERTED_ID = SCOPE_IDENTITY()
after inserting to table 1 and using in insert for table2, or inserting them to temp table and joining them to achieve the same results for table 3.
Here's the approach I'm taking with the CURSOR.
DECLARE #MyId as INT;
DECLARE #myCursor as CURSOR;
DECLARE #DESIRED_ROW_COUNT INT = 70000
DECLARE #ROWS_INSERTED INT = 0
DECLARE #CURRENT_ROW_COUNT INT = 0
DECLARE #NEWLY_INSERTED_ID INT
DECLARE #LANGUAGE_PAIR_IDS TABLE ( LangugePairId INT, NewId INT, SourceLanguage varchar(100), TargetLangauge varchar(100) )
WHILE (#ROWS_INSERTED < #DESIRED_ROW_COUNT)
BEGIN
SET #myCursor = CURSOR FOR
SELECT Id FROM MyTable
SET #CURRENT_ROW_COUNT = (SELECT COUNT(ID) FROM MyTable)
OPEN #myCursor;
FETCH NEXT FROM #myCursor INTO #MyId;
WHILE ##FETCH_STATUS = 0
BEGIN
IF ((#CURRENT_SUBMISSION_COUNT < #DESIRED_ROW_COUNT) AND (#ROWS_INSERTED < #DESIRED_ROW_COUNT))
BEGIN
INSERT INTO [dbo].[MyTable]
([Column1]
([Column2]
([Column3]
)
SELECT
,convert(numeric(9,0),rand() * 899999999) + 100000000
,COlumn2
,Colum3
FROM MyTable
WHERE Id = #MyId
SET #NEWLY_INSERTED_ID = SCOPE_IDENTITY()
INSERT INTO [dbo].[Language]
([MyTable1Id]
,[Target]
,[Source]
OUTPUT inserted.Id, inserted.MyTable1Id, inserted.Source, inserted.[Target] INTO #LANGUAGE_PAIR_IDS (LangugePairId, NewId, SourceLanguage, TargetLangauge)
SELECT
#NEWLY_INSERTED_ID
,[Target]
,[Source]
FROM [dbo].[Language]
WHERE MyTableId = #MyId
ORDER BY Id
DECLARE #tbl AS TABLE (newLanguageId INT, oldLanguageId INT, sourceLanguage VARCHAR(100), targetLanguage VARCHAR(100))
INSERT INTO #tbl (newLanguageId, oldLanguageId, sourceLanguage, targetLanguage)
SELECT 0, id, [Source], [Target] MyTable1Id FROM Language WHERE MyTable1Id = #MyId ORDER BY Id
UPDATE t
SET t.newlanguageid = lp.LangugePairId
FROM #tbl t
JOIN #LANGUAGE_PAIR_IDS lp
ON t.sourceLanguage = lp.SourceLanguage
AND t.targetLanguage = lp.TargetLangauge
INSERT INTO [dbo].[Manager]
([LanguagePairId]
,[UserId]
,[MyDate])
SELECT
tbl.newLanguageId
,p.[UserId]
,p.[MyDate]
FROM Manager m
INNER JOIN #tbl tbl
ON m.LanguagePairId = tbl.oldLanguageId
WHERE m.LanguagePairId in (SELECT Id FROM Language WHERE MyTable1Id = #MyId) -- returns the old language pair id
SET #ROWS_INSERTED += 1
SET #CURRENT_ROW_COUNT +=1
END
ELSE
BEGIN
PRINT 'REACHED EXIT'
SET #ROWS_INSERTED = #DESIRED_ROW_COUNT
BREAK
END
FETCH NEXT FROM #myCursor INTO #MyId;
END
CLOSE #myCursor
DEALLOCATE #myCursor
END
The above code works! It generates the data I need. However, it's very very slow. Just to give some comparison. Initial load of data for table 1 was ~60,000 records, Table2: ~74,000 and Tabl3 ~3,400
I tried to insert 9,000 rows in Table1. With the above code, it took 17:05:01 seconds to complete.
Any suggestion on how I can optimize the query to run little faster? My goal is to insert 1-2 mln records in Table1 without having to wait for days. I'm not tied to CURSOR. I'm ok to achieve the same result in any other way possible.

Cursor in SQL Server: Use loop / condition to find and replace a value

I have a issue with my table in SQL Server. Sometime during a insert a normal value (20-50-80) changed by 1000000. It's really rare but to secure the average i need to make a fix before finding a new solution.
I want to take the value that exceeds 1000000 and replace them by the average of the value between it.
This picture show the problem.
I'm looking at the Cursor in SQL.
Here a exemple of my code. Some issue about the result.
CREATE PROCEDURE [dbo].[Avg_Kwh_TagValuesArchive]
AS
BEGIN
DECLARE #tagId INT
DECLARE #localTime DATE
DECLARE #tagValue FLOAT
DECLARE #limit FLOAT
DECLARE #temp FLOAT
DECLARE #tagValueBefore FLOAT
DECLARE #tagValueAfter FLOAT
SET #limit = 999999.9
DECLARE Cursor_FalseValues CURSOR
FOR
SELECT TagID, LocalTime, TagValue
FROM TagValuesArchive
ORDER BY LocalTime DESC
OPEN Cursor_FalseValues
FETCH Cursor_FalseValues
INTO #tagId, #localTime, #tagValue
WHILE(##FETCH_STATUS = 0)
BEGIN
IF (#tagValue>=#limit)
BEGIN
SET #tagValueBefore =
(
SELECT TOP 1 TagValue
FROM TagValuesArchive
WHERE LocalTime < #localTime
AND TagID = #tagID
AND TagValue IS NOT NULL
ORDER BY LocalTime DESC
)
SET #tagValueAfter =
(
SELECT TOP 1 TagValue
FROM TagValuesArchive
WHERE LocalTime > #localTime
AND TagID = #tagID
AND TagValue IS NOT NULL
ORDER BY LocalTime DESC
)
UPDATE dbo.TagValuesArchive
SET TagValue= ((SUM( #tagValueBefore + #tagValueAfter ))/2)
FROM dbo.TagValuesArchive
WHERE LocalTime = #localTime
AND TagID = #tagID
FETCH NEXT FROM Cursor_FalseValues
INTO #tagId, #localTime, #tagValue
END
ELSE
BEGIN
-- Fetch of the Cursos increment the line
FETCH NEXT FROM Cursor_FalseValues
INTO #tagId, #localTime, #tagValue
END
-- Fetch of the Cursos increment the line
--FETCH NEXT FROM Cursor_FalseValues
--INTO #tagId, #localTime, #tagValue
END
CLOSE Cursor_FalseValues
DEALLOCATE Cursor_FalseValues
END
I think my problem is a good example to use Cursor, but it's not very clear in my head.
I can take the wrong value and the values between it. But the Update in the database doesn't work.
I don't know if it's a cursor problem or a update. Maybe just a code syntax problem.
Thanks for any informations.
You can try something like this:
DECLARE #t TABLE (
id int,
val float
)
INSERT INTO #t (id, val)
VALUES
(1,.5),
(2,.7),
(3,.3),
(4,.74),
(5,.2341234),
(6,10000000),
(7,.9),
(8,.8),
(9,.87123),
(10,100000000),
(11,.99)
SELECT * FROM #t
DECLARE #limit FLOAT = 1000000;
;WITH OutOfOBoundsValues AS (
SELECT id FROM #t WHERE val >= #limit
), Neighbourvalues AS (
SELECT O.id, (t1.val+t2.val)/2 newval FROM OutOfOBoundsValues O
JOIN #t t1 ON t1.id = O.id-1
JOIN #t t2 ON t2.id = O.id+1
)
UPDATE #t
SET val = N.newval
FROM #t t
JOIN Neighbourvalues N ON t.id = N.Id
SELECT * FROM #t
What happens here is that we select the data same as and above the limit.
Then we get the neighbouring values and calculates the mean value from them.
Lastly we update the out of bounds values with the mean value.
This should be much faster than your cursor.

How to iterate an int column for each distinct value in SQL?

I've been trying a query to update my current database but I can't figure out how to do it. I've been trying with cursors but I can't find a way to isolate each row and not set all the rows of the distinct column to the same value.
Here is what I have in my database:
RecoNumber Item
ABIBAQC-01 1
ABIBAQC-01 1
ABIBAQC-01 1
ABIBAQC-02 1
ABIBAQC-03 1
ABIBAQC-03 1
And I would like it to become:
RecoNumber Item
ABIBAQC-01 1
ABIBAQC-01 2
ABIBAQC-01 3
ABIBAQC-02 1
ABIBAQC-03 1
ABIBAQC-03 2
Like I said, I've tried with a cursor but I am missing something to make it work properly.
DECLARE #NUMBER INT
DECLARE #RECO NVARCHAR(10)
DECLARE #RECO_OLD NVARCHAR(10)
DECLARE db_cursor CURSOR FOR
SELECT DISTINCT RecoNumber
FROM Workbook2014_Test.dbo.Reco
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #RECO
SET #NUMBER = 1
SET #RECO_OLD = #RECO
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE Workbook2014_Test.dbo.Reco
SET Item = #NUMBER
WHERE RecoNumber = #RECO
FETCH NEXT FROM db_cursor INTO #RECO
IF(#RECO != #RECO_OLD)
SET #NUMBER = 1
ELSE
SET #NUMBER = #NUMBER + 1
END
CLOSE db_cursor
DEALLOCATE db_cursor
Thanks in advance for any tips.
You can use the ROW_NUMBER() function for this:
;WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY RecoNumber ORDER BY RecoNumber) AS UPD_Item
FROM YourTable
)
UPDATE cte
SET Item = UPD_Item
The ROW_NUMBER() function assigns a number to each row. PARTITION BY is optional, but used to start the numbering over for each value in a given field or group of fields, ie: if you PARTITION BY Some_Date then for each unique date value the numbering would start over at 1. ORDER BY of course is used to define how the counting should go, and is required in the ROW_NUMBER() function.
You can SELECT * FROM cte first to observe the new values before running the UPDATE, you may have other field values you'd prefer to ORDER BY.