SQL Server While Loop Insert into different lines - sql-server

How can I make it possible in SQL Developer 2012 using while loop?
If a value is higher than 1,000,000 (one million) split it into several lines.
For example if the value is 2,400,000 it will be in three lines with the following value 900,000 , 900,000 and 600,000 as shown in table 2 below.
Table 1
ID | Value
1 | 200,000
2 | 300,000
3 | 1,000,000
4 | 2,400,000
Table 2
ID | Value
1 | 200,000
2 | 300,000
3 | 1,000,000
4 | 900,0000
4 | 900,0000
4 | 600,0000

if object_id('tempdb..#test','U') is not null
drop table #test
create table #test (vals int)
insert into #test values (600000),(800000), (2400000)
declare #count int =0 -- psuedo group counter
declare #i int -- used to contain current row value
declare #prevval int -- used to step through values in table
declare #more int = 1 -- used to create infinite while
-- get the first value into #i
select top 1 #i= vals from #test order by vals
while #more = 1
begin
set #prevval = #i
select #count += 1
while (#i - 900000)>0
begin
select #i -= 900000
select #count,900000
end
select #count, #i
select top 1 #i=vals
from #test
where vals > #prevval
order by vals
if ##rowcount =0 -- no more data...
break
end

Related

How to select distinct rows, but repeat if it has a different row between the equal ones

Having data like this:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
I want to select the data based on where the text and bit columns are distinct, but based on some order, in this case the id, the data changes between two identical rows, it should duplicate this row on the selection.
So, if I use distinct on SQL, I would get rows 1 and 3, but I want to retreive rows 1, 3 and 4, because even 1 and 4 being identical, row 3 is between then when ordering by id.
With a larger dataset, like:
id text bit date
1 row 1 2016-11-24
2 row 1 2016-11-25
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
9 row 0 2016-12-02
10 row 1 2016-12-03
Again, selecting with distinct on text and bit columns, the query would retrieve rows 1,3,5 and 6, but actually I want rows 1,3,4,5,6,7,8 and 10.
;with tb(id,[text],[bit],[date]) AS (
SELECT 1,'row',1,'2016-11-24' union
SELECT 2,'row',1,'2016-11-25' union
SELECT 3,'row',0,'2016-11-26' union
SELECT 4,'row',1,'2016-11-27' union
SELECT 5,'foo',1,'2016-11-28' union
SELECT 6,'bar',1,'2016-11-29' union
SELECT 7,'row',1,'2016-11-30' union
SELECT 8,'row',0,'2016-12-01' union
SELECT 9,'row',0,'2016-12-02' union
SELECT 10,'row',1,'2016-12-03')
select t1.* from tb as t1
OUTER APPLY (select top 1 [text],[bit] from tb as tt where tt.id<t1.id order by id desc ) as t2
where t1.[text]!=isnull(t2.[text],'') or t1.[bit]!=isnull(t2.[bit],1-t1.[bit])
result set:
1 row 1 2016-11-24
3 row 0 2016-11-26
4 row 1 2016-11-27
5 foo 1 2016-11-28
6 bar 1 2016-11-29
7 row 1 2016-11-30
8 row 0 2016-12-01
10 row 1 2016-12-03
It seems that you need a row-by-row operator. You need to know if the new row is the same as the previous one or not. If it is, neglect it, if not, keep it. Here is my solution:
declare #text varchar(100)=(select [text] from Mytable where id = 1)
declare #bit bit = (select [bit] from Mytable where id = 1)
declare #Newtext varchar(100)
declare #Newbit bit
declare #Mytable table(id int, [text] varchar(100), [bit] bit)
Insert into #Mytable select id,text, bit from Mytable where id = 1
declare #counter int =2
while #counter<=(select COUNT(*) from MyTable)
Begin
select #Newtext=(select [text] from Mytable where id = #counter)
select #Newbit=(select [bit] from Mytable where id = #counter)
IF #Newtext!=#text or #Newbit!=#bit
Begin
Insert into #Mytable
select * from Mytable where id = #counter
End
set #text = #Newtext
set #bit = #Newbit;
set #counter = #counter+1
END
select * from #Mytable

How can I replace duplicate strings with increasing order in T-SQL?

I have a single row table:
Id | Description
---------------
1 #Hello#, Its 5 am. #Hello#, Its 9 am. #Hello# its 12 pm.
I want to replace these duplicate string #Hello# with an increasing order. I need output like
Id | Description
---------------
1 #Hello#, Its 5 am. #Hello1#, Its 9 am. #Hello2# its 12 pm
Try this one,
DECLARE #V_STR NVARCHAR(1000) = (SELECT [Description] FROM [Table1])
,#V_COUNT INT = 0
,#V_TMP NVARCHAR(100) = '#Hello#'
WHILE ((CHARINDEX(#V_TMP,#V_STR)) > 0)
BEGIN
SELECT #V_STR = STUFF(#V_STR,(CHARINDEX(#V_TMP,#V_STR)),LEN(#V_TMP),'#Hello'+CAST(#V_COUNT AS NVARCHAR)+'#')
SET #V_COUNT += 1
END
SELECT #V_STR

How to retrieve unique records having unique values in two columns from a table in SQL Server

I want to query a table where I need the result that contains unique values from two columns together. For e.g.
Table
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
1 | E50 | 40
1 | E60 | 20
2 | E30 | 90
2 | E20 | 10
2 | E90 | 10
3 | E90 | 10
3 | E60 | 10
For each EnquiryId, EquipmentId will be unique in the table. Now I want a result where I can get something like this
EnquiryId | EquipmentId | Price
-----------+--------------+-------
1 | E20 | 10
2 | E30 | 90
3 | E90 | 10
In the result each enquiryId present in the table should be displayed uniquely.
If suppose I have 3 EquipmentIds "E20,E50,E60" for EnquiryId "1".. Any random EquipmentId should be displayed from these three values only.
Any help would be appreciated. Thank you in advance.
QUERY
;WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY enquiryID
ORDER BY enquiryID ) AS RN
FROM tbl
)
SELECT enquiryID,equipmentID,Price
FROM cte
WHERE RN=1
FIND FIDDLE HERE
The following code must help you..
Sorry that I ended up in a lengthy solution only. Run it in your SSMS and see the result.
Declare #tab table (EnquiryId int, EquipmentId varchar(10),Price int)
Insert into #tab values
(1,'E20',10),
(1,'E50',40),
(1,'E60',20),
(2,'E30',90),
(2,'E20',10),
(2,'E90',10),
(3,'E90',10),
(3,'E60',10)
----------------------------------------------
Declare #s int = 1
Declare #e int,#z varchar(10)
Declare #Equipment table (EquipmentId varchar(10),ind int)
Insert into #Equipment (EquipmentId) Select Distinct EquipmentId From #tab
Declare #Enquiry table (id int identity(1,1),EnquiryId int,EquipmentId varchar(10))
Insert into #Enquiry (EnquiryId) Select Distinct EnquiryId From #tab
Set #e = ##ROWCOUNT
While #s <= #e
begin
Select Top 1 #z = T.EquipmentId
From #tab T
Join #Enquiry E On T.EnquiryId = E.EnquiryId
Join #Equipment Eq On Eq.EquipmentId = T.EquipmentId
Where E.id = #s
And Eq.ind is Null
Order by NEWID()
update #Enquiry
Set EquipmentId = #z
Where id = #s
update #Equipment
Set ind = 1
Where EquipmentId = #z
Set #s = #s + 1
End
Select T.EnquiryId,T.EquipmentId,T.Price
From #tab T
left join #Enquiry E on T.EnquiryId = E.EnquiryId
Where T.EquipmentId = E.EquipmentId
You can use GROUP BY (Typical way) to remove duplicate value.
Basic steps are:
Alter table & Add Identity Column.
Group by columns which can be dupicate.
Delete those record.
Check here Remove Duplicate Rows from a Table in SQL Server

Find specific word in column

I am using SQL Server 2008.
My tables are :
Location
------------------------
Id | LocationName
------------------------
1 | Bodakdev
2 | Thaltej Road
3 | Andheri East
4 | Noida Sector 2
Company
--------------------------------------------------------------------------
CId | Address | LocationId
--------------------------------------------------------------------------
11 | 301, GNFC Infotower, Bodakdev, | NULL
12 | 307/308,Arundeep Complex | NULL
13 | 7 Krishana Dyeing Compund, Nagardas rd., Andheri | NULL
14 | B-23 ,Ground Floor,Sector 2 | NULL
--------------------------------------------------------------------------
Currently LocationId in the Company table are null. If Address contains any location name then update LocationId.
For example, Address of CID - 11 contains Bodakdev then update LocationId 1, second example, Address of CID - 13 contains Andheri word then update LocationId 3.
Required output :
CId | Address | LocationId
--------------------------------------------------------------------------
11 | 301, GNFC Infotower, Bodakdev, | 1
12 | 307/308,Arundeep Complex | NULL
13 | 7 Krishana Dyeing Compund, Nagardas rd., Andheri | 3
14 | B-23 ,Ground Floor,Sector 2 | 4
--------------------------------------------------------------------------
I have tried using below query
SELECT
(LEN(Address) - LEN(REPLACE(Address, LocationName, '')) ) / LEN(LocationName)
if Address contains Location Name then it will return number of occurrences otherwise it return 0.
But it will not give correct output. How can I do this? Thanks. Any suggestion would be appreciated.
Try following Query :
1.STEP1 : make one function which can split the sting by any character and return the output in table format .
CREATE FUNCTION [dbo].[fnSplit](
#sInputList VARCHAR(8000) -- List of delimited items
, #sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS #List TABLE (item VARCHAR(8000))
BEGIN
DECLARE #sItem VARCHAR(8000)
WHILE CHARINDEX(#sDelimiter,#sInputList,0) <> 0
BEGIN
SELECT
#sItem=RTRIM(LTRIM(SUBSTRING(#sInputList,1,CHARINDEX(#sDelimiter,#sInputList,0)-1))),
#sInputList=RTRIM(LTRIM(SUBSTRING(#sInputList,CHARINDEX(#sDelimiter,#sInputList,0)+LEN(#sDelimiter),LEN(#sInputList))))
IF LEN(#sItem) > 0
INSERT INTO #List SELECT #sItem
END
IF LEN(#sInputList) > 0
INSERT INTO #List SELECT #sInputList -- Put the last item in
RETURN
END
2.STEP2 : use following query to get your desire output .
DECLARE #LOCATION AS TABLE (ID INT ,NAME VARCHAR(MAX))
DECLARE #COMPANY AS TABLE (CID INT , ADDRESS VARCHAR(MAX) , LOCATIONID INT)
INSERT INTO #LOCATION VALUES(1,'Bodakdev')
INSERT INTO #LOCATION VALUES(2,'Thaltej Road')
INSERT INTO #LOCATION VALUES(3,'Andheri East')
INSERT INTO #LOCATION VALUES(4,'Noida Sector 2')
INSERT INTO #COMPANY VALUES(11,'301, GNFC Infotower, Bodakdev,' , NULL)
INSERT INTO #COMPANY VALUES(12,'307/308,Arundeep Complex' , NULL)
INSERT INTO #COMPANY VALUES(11,'7 Krishana Dyeing Compund, Nagardas rd., Andheri' , NULL)
INSERT INTO #COMPANY VALUES(11,'B-23 ,Ground Floor,Sector 2' , NULL)
UPDATE #Company
SET
LOCATIONID = B.ID
FROM #COMPANY AS A , #LOCATION AS B
WHERE
1 = CASE WHEN
(
SELECT COUNT(*)
FROM FNSPLIT(B.NAME , ' ')
WHERE A.ADDRESS LIKE '%' + ITEM + '%'
) > 0 THEN 1 ELSE 0 END
This is the one way to do it . we can do it using full text searching also.

Performance Issue in While Clause

Okay everyone,
Apologies in advance for the length. This one's actually kind of fun, though.
I wrote up a SQL script that I was semi-proud of yesterday because I thought it was quite clever. Turns out it gets ruined by performance issues, and I can't even test it because of that, so it may not even be doing what I think sigh.
This problem is best explained with an example:
Column A | Column B | Column C | Column D
Heart | K | 2/1/2013 | 3/1/2013
Heart | K | 2/1/2013 | 3/1/2013
Heart | K | 1/1/2013 | 3/1/2013
Heart | K | 2/1/2013 | 4/1/2013
Spade | 4 | 2/1/2013 | 3/1/2013
Spade | 3 | 2/1/2013 | 3/1/2013
Club | 4 | 2/1/2013 | 3/1/2013
With this table I need to: 1. Starting with the first, update the row with the data following it if the values in Column A match, 2. delete the second row after the update if there was a match, and 3. move on to the next row if there was no match and rerun the same process.
If there's a match, the higher row updates based on the following:
Column A: Nothing
Column B: If both values are the same, keep the value in one, otherwise write 'Multiple'
Column C: Keep the earlier date between the two,
Column D: Keep the later date between the two,
Then I delete the lower row.
My example should result in the following:
Column A | Column B | Column C | Column D
Heart | K | 1/1/2013 | 4/1/2013
Spade | Multiple | 2/1/2013 | 3/1/2013
Club | 4 | 2/1/2013 | 3/1/2013
To do all this I created two table variables, inserted the same data into both, and then cycled through the second (#ScheduleB) looking for matches to update the row in the first table (#ScheduleA). I then deleted the row below the row in #A (because it's the same as B). Finally, when there wasn't a match, I moved to the next row in #A to start the process over. At least that's what the code's supposed to do -- see below.
The problem is performance is TERRIBLE. I've considered using a Cursor, but don't know if the performance would help there.
Any suggestions?
Declare #ScheduleA Table
(
RowNumber int,
Period nvarchar(MAX),
Program nvarchar(MAX),
ControlAccount Nchar(50),
WorkPackage Nchar(50),
CAM Nchar(50),
EVM Nchar(50),
Duration int,
BLStart datetime,
BLFinish datetime
)
Declare #ScheduleB Table
(
RowNumber int,
Period nvarchar(MAX),
Program nvarchar(MAX),
ControlAccount Nchar(50),
WorkPackage Nchar(50),
CAM Nchar(50),
EVM Nchar(50),
Duration int,
BLStart datetime,
BLFinish datetime
)
Insert INTO #ScheduleA
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData
where program = #Program and period = #Period
Insert INTO #ScheduleB
Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,
ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
From ScheduleData
where program = #Program and period = #Period
declare #i int = 1
declare #j int = 2
--Create a loop for the second variable that counts up to the last row of the B table
While #j < (select MAX(ROWNUMBER) + 1 from #ScheduleB)
Begin
--if the tables match by WorkPackage THEN
IF ((select WorkPackage from #ScheduleA where RowNumber = #i) =
(select workpackage from #ScheduleB where RowNumber = #j))
Begin
Update #ScheduleA
--Update the Schedule CAM, BLStart, BLFinish of the A table (if necessary)
set CAM =
Case
--Set values in #ScheduleA Column B based on logic
End,
BLStart =
Case
--Set values in #ScheduleA Column C based on logic
End,
BLFinish =
Case
--Set values in #ScheduleA Column D based on logic
End
Where RowNumber = #i
Delete from #ScheduleA
where RowNumber = #i + 1
set #j = #j + 1 --next row in B
End
ELSE
set #i = #i + 1
END
EDIT: To clarify, column B is NOT an integer column, I was simply using this as an example because cards are pretty easily understood. I've since updated the column to include K's.
Based on your requirements I think a solution like this would work:
SELECT
[column a],
CASE WHEN MAX([column b]) <> MIN([column b]) THEN 'multiple' ELSE CAST(MAX([column b]) AS NVARCHAR(10)) END,
MIN([column c]),
MAX([column d])
FROM Table
GROUP BY [column a]
EDIT:
SQL Fiddle

Resources