There has to be a simpler way to do this, right? I have 100 rows of numeric values, and I want the first row to be in a new table, row 1 column A, second row to be in the new table, row 1 column B, ... 100th row to be in the new table, row 100 column J. Just for fun, I'm also writing a single letter based on that numeric value into the new table, instead of a numeric. So here's my code:
UPDATE #data
SET Block = CASE OStatus WHEN 1 THEN 'C' WHEN 2 THEN 'B'
WHEN 3 THEN 'D' WHEN 4 THEN 'S' WHEN 5 THEN 'P' ELSE '' END
DECLARE #Ax NVARCHAR(1)
,#Bx NVARCHAR(1)
,#Cx NVARCHAR(1)
,#Dx NVARCHAR(1)
,#Ex NVARCHAR(1)
,#Fx NVARCHAR(1)
,#Gx NVARCHAR(1)
,#Hx NVARCHAR(1)
,#Ix NVARCHAR(1)
,#Jx NVARCHAR(1)
SET #Count1 = 0
WHILE #Count1 < 10 BEGIN
SET #Count1 += 1
SELECT #Ax = Block FROM #data WHERE ID = #Count1 + 0
SELECT #Bx = Block FROM #data WHERE ID = #Count1 + 10
SELECT #Cx = Block FROM #data WHERE ID = #Count1 + 20
SELECT #Dx = Block FROM #data WHERE ID = #Count1 + 30
SELECT #Ex = Block FROM #data WHERE ID = #Count1 + 40
SELECT #Fx = Block FROM #data WHERE ID = #Count1 + 50
SELECT #Gx = Block FROM #data WHERE ID = #Count1 + 60
SELECT #Hx = Block FROM #data WHERE ID = #Count1 + 70
SELECT #Ix = Block FROM #data WHERE ID = #Count1 + 80
SELECT #Jx = Block FROM #data WHERE ID = #Count1 + 90
INSERT INTO _dbh_grid
SELECT
#Ax,#Bx,#Cx,#Dx,#Ex,#Fx,#Gx,#Hx,#Ix,#Jx
END
I use the PIVOT functionality (and a little math) to make it work; you could probably make it dynamic.
/*build a sample data set*/
SELECT TOP 100
column_id AS OSStatus
, ID = IDENTITY( INT, 1,1)
INTO #data
FROM sys.columns
WHERE column_id < 6;
SELECT *
FROM #data d;
/*break the data set into groups of 10, and identify the ordinal position within each group
column_postition returns group
row_position returns ordinal within group
*/
WITH c AS ( SELECT OSStatus
, column_position = ( ROW_NUMBER() OVER ( ORDER BY ID )
- 1 ) / 10
, row_position = ( ROW_NUMBER() OVER ( ORDER BY ID ) - 1 )
% 10
FROM #data
)
SELECT [A], [B], [C], [D], [E], [F], [G], [H], [I], [J]
FROM ( SELECT c.OSStatus
, column_name = CHAR(65 + c.column_position) --convert to a-J
, c.row_position
FROM c
) p
PIVOT
(MIN(OsStatus)
FOR column_name
IN ([A], [B], [C], [D], [E], [F], [G], [H], [I], [J])
) pvt
DROP TABLE #data;
Related
Getting error:
Msg 512, Level 16, State 1, Line 48
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Msg 512, Level 16, State 1, Line 87
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Need to check each record in the table and update a table if there is no records = to 0,00. Then update an existing table with current values. I want to be able to track current data and compare with old data.
DECLARE #LocTime DATETIME;
DECLARE #MinDateTime DATETIME;
DECLARE #SystemDateTime DATETIME;
DECLARE #LIR MONEY;
DECLARE #LOAR MONEY;
SELECT #SystemDateTime = SYSDATETIME(); --= '2016-12-07 23:30:00'
SELECT #MinDateTime = DATEADD(mi,-30,#SystemDateTime) --go back half hour of reads, job is running every 10 minutes for overlap
--select #MinDateTime, #SystemDateTime
IF OBJECT_ID(N'tempdb..##LastOver2') IS NOT NULL
BEGIN
DROP TABLE ##LastOver2
END
--make temp table to hold found data
CREATE TABLE ##LastOver2 (ReadDate DATETIME
, FacilityName NVARCHAR(100)
, FacilityID UNIQUEIDENTIFIER
, LastInstantRead MONEY
, LastOverAllRead MONEY
, FacilityTimeZone INT
, FacilityTime DATETIME)
INSERT INTO ##LastOver2 (ReadDate, FacilityName
, FacilityID, LastInstantRead
, LastOverAllRead
, FacilityTimeZone, FacilityTime)
SELECT DISTINCT --why distinct?
fmr.ReadDate, f.Name
, f.FacilityID, fm.LastInstantRead
, fm.LastOverAllRead
, f.Timezone
, #LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK)
ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK)
ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime and ReadDate <= #SystemDateTime) --including on both side to continue with overlap
and (fm.IsVirtual = 0 and fm.ParentMeterID is NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0
select * from ##LastOver2
IF (select LastInstantRead from ##LastOver2) = 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) = 0.00
BEGIN
--UPDATE dbo.Facilities
--SET SuppressMonitoring = 1
-- FROM dbo.Facilities F
-- JOIN ##LastOver L
-- ON F.FacilityID = l.FacilityID
-- WHERE F.FacilityID = l.FacilityID
DECLARE #body_content NVARCHAR(150);
DECLARE #StartHour NVARCHAR(8) = '08:30:00' ;
DECLARE #StopHour NVARCHAR(8) = '16:00:00';
--why distinct, is it already distinct. Is is supposed to distinct the facility or meter?
DECLARE #SQLScript NVARCHAR(200) = 'SELECT distinct * FROM ##LastOver2 WHERE CONVERT(TIME, FacilityTime) BETWEEN '
+ CHAR(39) + #StartHour + CHAR(39) +' AND ' + CHAR(39) + #StopHour + CHAR(39);
--only looking for reads during day hours? shouldn't use between.
DECLARE #copyRecipients NVARCHAR(100)
SET #body_content = 'Please check the attached file. This was from server: ' + ##SERVERNAME
DECLARE #fileName nvarchar(255);
select #fileName = 'BadReading_' + replace(replace(convert(nvarchar(19),getdate(), 126),':',''),'-','') + '.txt';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SQLSupport'
,#recipients = 'Btest#test.com'
--, #recipients = 'jira#cleanenergycollective.atlassian.net'
--, #copy_recipients= #copyRecipients
--, #copy_recipients= 'Bill.Lugaila#easycleanenergy.com;yvonne.lewis#easycleanenergy.com;don.munroe#easycleanenergy.com;Justin.Reed#easycleanenergy.com'
, #query = #SQLScript
, #subject = 'Facility Meter Check and Updating table' --change so easier to see in emails
, #body= #body_content
, #importance= 'High'
, #attach_query_result_as_file = 1
, #query_attachment_filename = #fileName ;
--select #SQLScript
END
ELSE IF (select LastInstantRead from ##LastOver2) != 0.00 OR (SELECT LastOverAllRead FROM ##LastOver2) != 0.00
BEGIN
UPDATE [dbo].[_LastInstant_OverAll_Read]
SET [FacilityName] = lo.FacilityName,
[LastInstantRead] = lo.LastInstantRead,
[LastOverAllRead]= lo.LastOverAllRead,
[Time_Date] = (SELECT CONVERT(DateTime, SysDateTime()))
FROM ##LastOver2 lo
WHERE lo.FacilityName = [dbo].[_LastInstant_OverAll_Read].FacilityName
AND lo.LastInstantRead != [dbo].[_LastInstant_OverAll_Read].LastInstantRead
AND lo.LastOverAllRead != [dbo].[_LastInstant_OverAll_Read].LastOverAllRead
END
the following could be returning multiple rows:
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) = 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) = 0.00
.
.
.
IF
(
SELECT LastInstantRead
FROM ##LastOver2
) != 0.00
OR
(
SELECT LastOverAllRead
FROM ##LastOver2
) != 0.00
if you are expecting them to return only 1 row then you will need to fix the issue with the following query:
SELECT DISTINCT --why distinct?
fmr.ReadDate,
f.Name,
f.FacilityID,
fm.LastInstantRead,
fm.LastOverAllRead,
f.Timezone,
#LocTime
FROM [dbo].[Facilities] f WITH (NOLOCK)
JOIN [dbo].[FacilityMeters] fm WITH (NOLOCK) ON F.FacilityID = FM.FacilityID
JOIN FacilityMeterReadings fmr WITH (NOLOCK) ON FM.FacilityMeterID = FMR.FacilityMeterID
WHERE --fm.FacilityMeterID = '9268d1af-cc29-432c-9cdb-06c158180d2f'
(fmr.ReadDate >= #MinDateTime
AND ReadDate <= #SystemDateTime) --including on both side to continue with overlap
AND (fm.IsVirtual = 0
AND fm.ParentMeterID IS NULL)
--and (fm.LastInstantRead = 0.00 and fm.LastOverAllRead = 0.00)
AND f.SuppressMonitoring = 0;
Let us say I have some data I would like to repeat N times. A naive approach would be this:
IF OBJECT_ID('dbo.Data', 'U') IS NOT NULL
DROP TABLE dbo.Data
CREATE TABLE Data
(
DataId INT NOT NULL PRIMARY KEY,
DataValue NVARCHAR(MAX) NOT NULL
)
INSERT INTO Data (DataId, DataValue)
SELECT 1, 'Value1' UNION ALL
SELECT 2, 'Value2' UNION ALL
SELECT 3, 'Value3' UNION ALL
SELECT 4, 'Value4' UNION ALL
SELECT 5, 'Value5'
DECLARE #RowsRequired INT
DECLARE #Counter INT
DECLARE #NumberOfRows INT
SET #RowsRequired = 22
IF OBJECT_ID('tempdb..#TempData') IS NOT NULL DROP TABLE #TempData
CREATE TABLE #TempData
(
Id INT IDENTITY(1,1),
DataValue NVARCHAR(MAX)
)
SELECT #NumberOfRows = COUNT(*) FROM Data
SET #Counter = 1
WHILE #RowsRequired > 0
BEGIN
INSERT INTO #TempData
SELECT DataValue FROM Data WHERE DataId = #Counter
SET #Counter = #Counter + 1
SET #RowsRequired = #RowsRequired - 1
IF(#Counter > #NumberOfRows)
BEGIN
SET #Counter = 1
END
END
SELECT * FROM #TempData
Here #RowsRequired determines how many rows are required. Could this be rephrased in a set based form? Thanks.
Here is a SQLFiddle with the code.
Try this instead:
DECLARE #RowsRequired INT = 22
;WITH CTE AS
(
SELECT DataId, DataValue, ROW_NUMBER() over (PARTITION BY DataId ORDER BY DataId) sort
FROM DATA
CROSS JOIN
(
SELECT TOP (#RowsRequired) 0 d
FROM master..spt_values
) d
)
SELECT TOP (#RowsRequired) ROW_NUMBER() over (order by sort), DataValue
FROM CTE
ORDER BY sort, 1
I tried this and worked for me.
declare #requiredrows int
set #requiredrows = 22;
declare #foreachrow int
select #foreachrow = #requiredrows / Count(*) from Data;
select top (#requiredrows) * from
(
select *, ROW_NUMBER() over(partition by dataId order by number) rno
from Data
Cross Join master..spt_values
) A
where rno <= #foreachrow + 1
Hope it will help.
I'm trying to anonymize all the data in my database, so I'm renaming all the people in it. I asked a similar question earlier, and was told to use NewID to force the creation of a new value per updated row, but in this situation it doesn't seem to be working.
What am I doing wrong?
-- Create Table Customer
CREATE TABLE #FirstName
(
ID int,
FirstName nvarchar(255) NULL,
Gender nvarchar(255) NULL
)
CREATE TABLE #LastName (
ID int,
LastName nvarchar(255)
)
-- BULK INSERT to import data from Text or CSV File
BULK INSERT #FirstName
FROM 'C:\Users\jhollon\Desktop\tmp\names\firstnames.lined.txt'
WITH
(
FIRSTROW = 1,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
BULK INSERT #LastName
FROM 'C:\Users\jhollon\Desktop\tmp\names\lastnames.lined.txt'
WITH
(
FIRSTROW = 1,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
/*SELECT FirstName FROM #FirstName WHERE ID = (
SELECT RandomNumber FROM (
SELECT ABS(CHECKSUM(NewID())) % 1500 AS RandomNumber FROM tblTenant WHERE Sex = '1'
) AS A
);*/
UPDATE tblTenant SET TenantName = (
SELECT LastName + ', ' + FirstName FROM
(SELECT UPPER(FirstName) as FirstName FROM #FirstName WHERE ID = (SELECT ABS(CHECKSUM(NewID())) % 500 + 1501)) AS A,
(SELECT LastName FROM #LastName WHERE ID = (SELECT ABS(CHECKSUM(NewID())) % 200 + 1)) as B
) WHERE Sex = '2';
UPDATE tblTenant SET TenantName = (
SELECT LastName + ', ' + FirstName FROM
(SELECT UPPER(FirstName) as FirstName FROM #FirstName WHERE ID = (SELECT ABS(CHECKSUM(NewID())) % 500 + 1)) AS A,
(SELECT LastName FROM #LastName WHERE ID = (SELECT ABS(CHECKSUM(NewID())) % 200 + 1)) as B
) WHERE Sex = '1';
DROP TABLE #FirstName;
DROP TABLE #LastName;
Correct. The subquery is evaluated once which is as advertised ("cachable scalar subquery")
Try this which uses NEWID as a derived table
UPDATE T
SET
TenantName = L.LastName + ', ' + F.FirstName
FROM
tblTenant T
CROSS APPLY
(SELECT TOP 1 UPPER(FirstName) as FirstName FROM #FirstName
WHERE CHECKSUM(NEWID()) <> T.ID
ORDER BY NEWID()) F
CROSS APPLY
(SELECT TOP 1 LastName FROM #LastName
WHERE CHECKSUM(NEWID()) <> T.ID
ORDER BY NEWID()) L
I'm not sure I understand your question, but if you want the ID to be unique values, you can make it an identity column.
Ex:
[ID] [int] IDENTITY(1,1) NOT NULL
The code below demonstrates that without an inner to outer correlation, that the old name is not guaranteed to differ from the new name when using the CROSS APPLY answer above.
WHERE F.Id <> T.Id ORDER BY NEWID() would be better within the FirstName CROSS APPLY
USE tempdb
GO
IF OBJECT_ID('tblTenant') IS NOT NULL
DROP TABLE tblTenant
GO
CREATE TABLE tblTenant
(
Id int,
FirstName nvarchar(20),
LastName nvarchar(20),
Gender bit
)
INSERT INTO tblTenant
VALUES (1, 'Bob' , 'Marley', 1),
(2, 'Boz' , 'Skaggs', 1)
SELECT DISTINCT FirstName
INTO #FirstNames
FROM tblTenant
SELECT DISTINCT LastName
INTO #LastNames
FROM tblTenant
-- There is a probability > 0 that a tenant's new name = tenants old name
SELECT
OldFirst = T.FirstName,
OldLast = T.LastName,
NewFirst = F.FirstName,
NewLast = L.LastName
FROM
tblTenant T
CROSS APPLY
(
SELECT TOP 1 UPPER(FirstName) AS FirstName
FROM #FirstNames
WHERE CHECKSUM(NEWID()) <> T.ID
ORDER BY NEWID()
) F
CROSS APPLY
(
SELECT TOP 1 LastName
FROM #LastNames
WHERE CHECKSUM(NEWID()) <> T.ID
ORDER BY NEWID()
) L
How can I generate a random string?
I wrote the following, which gave my only one letter as a result !
declare #alphaCount int
set #alphaCount = #alphaCount +1
CHAR(#alphaCount)
Thanks in advance!
This will give you 10,000 rows in the specified format.
DECLARE #Numbers TABLE
(
n INT PRIMARY KEY
);
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1), --2
E02(N) AS (SELECT 1 FROM E00 a, E00 b), --4
E04(N) AS (SELECT 1 FROM E02 a, E02 b), --16
E08(N) AS (SELECT 1 FROM E04 a, E04 b), --256
E16(N) AS (SELECT 1 FROM E08 a, E08 b) --65,536
INSERT INTO #Numbers
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM E16
SELECT CAST((SELECT TOP 20 CHAR(CASE
WHEN Abs(Checksum(Newid()))%2 = 0 THEN 65
ELSE 97
END + Abs(Checksum(Newid()))%26)
FROM #Numbers n1
WHERE n1.n >= -n2.n /*So it gets re-evaluated for each row!*/
FOR XML PATH('')) AS CHAR(20))
FROM #Numbers n2
Fill a temporary table with a list of random words. Then use CROSS JOIN to combine every word with every other word, to get a whole ton of data with little effort.
select l.word+' '+r.word from #Words as l
cross join #Words as r
This procedure will work. You may have to create a function with it, but it has the right ideas.
This should do the trick for how to
DECLARE #length Integer
DECLARE #return VarChar(1000)
DECLARE #index Integer
DECLARE #value Integer
SET #length = 12
SET #return = '';
IF #length > 1000
SET #length = 1000;
IF #length <= 0
SELECT #return;
SET #index = 0;
WHILE #index < #length
BEGIN
SET #value = (64 * RAND()) + 32;
SET #return = #return + CHAR(#value);
SET #index = #index + 1;
END
SELECT #return;
If you wanted to make this a user defined function, i liked the option 'steve' had in this article. here
I have this statement in T-SQL.
SELECT Bay From TABLE where uid in (
select B_Numbers from Info_Step WHERE uid = 'number'
)
I am selecting "multiple" BAYs from TABLE where their uid is equal to a string of numbers like this:
B_Numbers = 1:45:34:98
Therefore, I should be selecting 4 different BAYs from TABLE. I basically need to split the string 1:45:34:98 up into 4 different numbers.
I'm thinking that Split() would work, but it doesn't and I get a syntax error.
Any thoughts from the T-SQL gods would be awesome!
Here is an implementation of a split function that returns the list of numbers as a table:
http://rbgupta.blogspot.com/2007/03/split-function-tsql.html
Looks like this would set you on your way...
Here is a method that uses an auxiliary numbers table to parse the input string. The logic can easily be added to a function that returns a table. That table can then be joined to lookup the correct rows.
Step 1: Create the Numbers table
SET NOCOUNT ON
GO
IF EXISTS
(
SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Numbers'
AND TABLE_SCHEMA = 'dbo'
AND TABLE_TYPE = 'BASE TABLE'
)
BEGIN
DROP TABLE dbo.Numbers
END
GO
CREATE TABLE dbo.Numbers
(
Number smallint IDENTITY(1, 1) PRIMARY KEY
)
GO
WHILE 1 = 1
BEGIN
INSERT INTO dbo.Numbers DEFAULT VALUES
IF SCOPE_IDENTITY() = 32767
BEGIN
BREAK
END
END
GO
Step 2: Parse the Input String
CREATE FUNCTION dbo.ParseString(#input_string varchar(8000), #delim varchar(8000) = " ")
RETURNS TABLE
AS RETURN
(
SELECT Number
FROM dbo.Numbers
WHERE CHARINDEX
(
#delim + CONVERT(VARCHAR(12),Number) + #delim,
#delim + #input_string + #delim
) > 0
)
GO
**EXAMPLE**
SELECT * FROM dbo.ParseString('1:45:34:98',':')
Step 3: Use the results however you want/need
Number
------
1
34
45
98
End-To-End Example
Create function that returns the appropriate BNumber (of course change it to use the commented out SQL)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION dbo.GetBNumber (#uid int)
RETURNS VARCHAR(8000)
AS
BEGIN
RETURN '1:45:34:98'
--select B_Numbers from Info_Step WHERE uid = #uid
END
GO
Use the use functions to return the desired results
-- Using Test Data
SELECT N.Number FROM Numbers N
JOIN dbo.ParseString(dbo.GetBNumber(12345),':') Q ON Q.Number = N.Number
-- Using Your Data (Untested but should work.)
SELECT N.Bay
FROM TABLE N
JOIN dbo.ParseString(dbo.GetBNumber(ENTER YOU NUMBER HERE),':') Q ON Q.Number = N.uid
Results
Number
------
1
34
45
98
You should keep your arrays as rows but if I understand your question I think this will work.
SELECT
Bay
From
TABLE
join Info_Step
on B_Numbers like '%'+ uid +'%'
where
Info_Step.uid = 'number'
This query will do a full table scan because of the like operator.
What you can do is loop through the B_Numbers entries and do your own split on : Insert those entries into a temp table and then perform your query.
DECLARE #i int
DECLARE #start int
DECLARE #B_Numbers nvarchar(20)
DECLARE #temp table (
number nvarchar(10)
)
-- SELECT B_Numbers FROM Info_Step WHERE uid = 'number'
SELECT #B_Numbers = '1:45:34:98'
SET #i = 0
SET #start = 0
-- Parse out characters delimited by ":";
-- Would make a nice user defined function.
WHILE #i < len(#B_Numbers)
BEGIN
IF substring(#B_Numbers, #i, 1) = ':'
BEGIN
INSERT INTO #temp
VALUES (substring(#B_Numbers, #start, #i - #start))
SET #start = #i + 1
END
SET #i = #i + 1
END
-- Insert last item
INSERT INTO #temp
VALUES (substring(#B_Numbers, #start, #i - #start + 1))
-- Do query with parsed values
SELECT Bay FROM TABLE WHERE uid in (SELECT * FROM #temp)
You can even try this
declare #str varchar(50)
set #str = '1:45:34:98'
;with numcte as(
select 1 as rn union all select rn+1 from numcte where rn<LEN(#str)),
getchars as(select
ROW_NUMBER() over(order by rn) slno,
rn,chars from numcte
cross apply(select SUBSTRING(#str,rn,1) chars)X where chars = ':')
select top 1
Bay1 = SUBSTRING(#str,0,(select rn from getchars where slno = 1))
,Bay2 = SUBSTRING(#str,
(select rn from getchars where slno = 1) + 1,
(((select rn from getchars where slno = 2)-
(select rn from getchars where slno = 1)
)-1))
,Bay3 = SUBSTRING(#str,
(select rn from getchars where slno = 2) + 1,
(((select rn from getchars where slno = 3)-
(select rn from getchars where slno = 2)
)-1))
,Bay4 = SUBSTRING(#str,
(select rn from getchars where slno = 3)+1,
LEN(#str))
from getchars
Output:
Bay1 Bay2 Bay3 Bay4
1 45 34 98