Fixed array and random numbers in an SQL query - sql

What's the easiest way to select one of five fixed strings returned in an SQL Server query, randomly?
I.e. the equivalent of:
function randomColumn() {
var values = ['apple', 'banana', 'orange', 'cherry', 'lemon'];
var idx = Math.floor(Math.random() * 5);
return values[idx];
}
I need to change my existing SQL script to have a certain column return one of these values, without the need to change my client code.
Do I need to create a temp table?
I'm using SQL Server 2008 R2.

You don't need a temporary table for a few strings, you can create the result on the fly:
select str
from (
select 0 as id, 'apple' as str
union all
select 1, 'banana'
union all
select 2, 'orange'
union all
select 3, 'cherry'
union all
select 4, 'lemon'
) x
where id = floor(rand() * 5)

select top 1 Value
from Table1
order by newid()
SQL Fiddle Example

Select 'apple' values
INTO #tmp
UNION ALL
Select'banana' values
UNION ALL
Select 'orange' values
.
.
.
select top 1 values
from #tmp
order by newid()
OR
ALTER TABLE #tmp
ADD id BIGINT IDENTITY(1,1)
DECLARE #rand BIGINT
SET #rand=rand()*4
select top 1 values
from #tmp
where id=#rand

DECLARE #ListofIDs TABLE(IDs VARCHAR(100), ID INT IDENTITY(1,1));
INSERT INTO #ListofIDs
SELECT 'a'
UNION ALL
SELECT 'b'
UNION ALL
SELECT '20'
UNION ALL
SELECT 'c'
UNION ALL
SELECT '30'
UNION ALL
SELECT 'd';
SELECT * FROM #ListofIDs;
SELECT Ids from #ListofIDs where ID=1+ CONVERT(INT, (5)*RAND())

Related

SQL Server using Except vs Binary_Checksum

I am using SQL Server and want to do Bulk Updates but don't want any row to be re-updated if same values already exists.
For Example Consider following tables with their data
DECLARE #UpdatedIds TABLE
(
BookId INT
)
CREATE TABLE Book
(
[Id] INT,
[Name] NVARCHAR(MAX)
)
INSERT INTO Book([Id], [Name])
SELECT 1, 'Book1'
UNION
SELECT 2, 'Book2'
UNION
SELECT 3, 'Book3'
UNION
SELECT 4, 'Book4'
UNION
SELECT 5, 'Book5'
CREATE TABLE #Book
(
[Id] INT,
[Name] NVARCHAR(MAX)
)
INSERT INTO #Book([Id], [Name])
SELECT 1, 'Book1_Changed'
UNION
SELECT 2, 'Book2_Changed'
UNION
SELECT 3, 'Book3'
UNION
SELECT 4, 'Book4'
UNION
SELECT 5, 'Book5'
What I want is when I run the following query
UPDATE [BO]
SET [Name] = [BU].[Name]
OUTPUT [INSERTED].[Id] INTO #UpdatedIds([BookId])
FROM [Book] [BO]
INNER JOIN #Book [BU] ON [BO].[Id] = [BU].[Id]
SELECT * FROM #UpdatedIds
#UpdatedIds should have records of 1 and 2 not 3, 4, or 5
I have 2 ways of doing this in my mind and would like to have opinions about which one will be fastest/better.
Using Except Keyword and delete rows that already exists
Using Binary_Checksum that is comparing Checksums of records in actual table and in temp table and removing records with equal checksum
Thanks

SQL paging with non-fixed-length page size

The table is simple: It has 2 columns, id and type. The type can be 1 or 2.
Now I want the first 10 entries with type 1, in a sequence ordered by id, and if there are type 2 entries somewhere in between then they should be included in the result set too. What is the SQL query?
It's basically paging but the number of rows per page can vary so can't use OFFSET and LIMIT.
For SQL Server you can use CTE to make request for type 1 records once and then union with records of Type 2.
I selected only 5 rows to use less test data.
create table #TEST (Id int, Type int)
insert into #TEST
select 1,2 union
select 2,1 union
select 3,1 union
select 4,2 union
select 5,2 union
select 6,1 union
select 7,1 union
select 8,2 union
select 9,1 union
select 10,1 union
select 11,2 union
select 12,2 union
select 13,1 union
select 14,1 union
select 15,1
go
with list1 (Id, Type)
as
(
select *
from #Test
where Type = 1
order by Id
offset 0 rows fetch next 5 rows only
)
select *
from list1
union all
select *
from #Test
where Type = 2 and Id > (select min(Id) from list1) and Id < (select max(Id) from list1)
order by Id
Should look something like this:
DECLARE #limit int = 25, #offset int = 10
DECLARE #ret TABLE (
ID INT,
TYPEID INT)
INSERT INTO #ret
SELECT Id, TypeId
FROM Logs
WHERE TypeId = 1
ORDER BY id
LIMIT #limit OFFSET #offset;
INSERT INTO #ret
SELECT id, TypeId
FROM Logs
WHERE TypeId = 2
AND ID BETWEEN (SELECT MAX(ID) FROM #ret) AND (SELECT MIN(ID) FROM #ret)
SELECT *
FROM #ret
ORDER BY ID
You could collapse this into a single SQL statement using a UNION, but it would have to query for the same data (limit and offset) more than once.

Join two tables multiple times on same column with a lookup table in between

This has probably been answered but, its hard to search for this question, as you can see in my confusing title.
Anyhow, I hope this example will help:
The tricky part is the one to many relationship in the parameter lookup table.
Ive tried using multiple joins and aliases resulting in a hugh number of rows since Im getting every 'amount' for every 'price'.
SELECT paraval.month, paraval.value as amount, paraval2.value as price, trade.position
FROM trade
INNER JOIN parameter para on trade.tID=para.tID and para.name = 'amount'
INNER JOIN parametervalues paraval on para.pID=paraval.pID
INNER JOIN parameter para2 on trade.tID=para2.tID and para2.name = 'price'
INNER JOIN parametervalues paraval2 on para2.pID=paraval2.pID
WHERE trade.type = 'cert'
Guessing I need sub-queries, but not sure where to place them.
EDIT add some SQL code structure :
CREATE TABLE #Trade
(
tID int PRIMARY KEY,
type varchar(50),
position int
);
CREATE TABLE #Parameter
(
pID int PRIMARY KEY,
tID int,
name varchar(50)
);
CREATE TABLE #ParameterValue
(
pID int,
smonth varchar(50),
value varchar(50));
INSERT INTO #Trade
SELECT 1, 'stock', 1
UNION
SELECT 2, 'stock', 2
UNION
SELECT 3, 'cert', 3
INSERT INTO #Parameter
SELECT 1,1,'amount'
UNION
SELECT 2,1,'price'
UNION
SELECT 3,2,'amount'
UNION
SELECT 4,2,'price'
UNION
SELECT 5,3,'amount'
UNION
SELECT 6,3,'price'
INSERT INTO #ParameterValue
SELECT 1,1,'5'
UNION
SELECT 2,1,'500'
UNION
SELECT 3,1,'15'
UNION
SELECT 4,1,'300'
UNION
SELECT 5,1,'5'
UNION
SELECT 5,2,'10'
UNION
SELECT 5,3,'5'
UNION
SELECT 6,1,'100'
UNION
SELECT 6,2,'200'
UNION
SELECT 6,3,'300'
-- SELECT * FROM #Trade
-- SELECT * FROM #Parameter
-- SELECT * FROM #ParameterValue
DROP TABLE #Trade
DROP TABLE #Parameter
DROP TABLE #ParameterValue
I think the best way for build your excepted output and relevant schema you have to use pivot with dynamic sql because in next day it possible to have some new values it’s the principal of your structure.
But i think this query can be respond :
SELECT paraval.month, (case when para. name = 'amount' then max(paraval.value) else null end)as amount, (case when para. name = 'price' then max(paraval.value) else null end) as price, max(trade.position) as position
FROM trade
INNER JOIN parameter para on trade.tID=para.tID
INNER JOIN parametervalues paraval on para.pID=paraval.pID
WHERE trade.type = 'cert'
Group by paraval.month
EDIT correction off previous query :
CREATE TABLE #Trade
(
tID int PRIMARY KEY,
type varchar(50),
position int
);
CREATE TABLE #Parameter
(
pID int PRIMARY KEY,
tID int,
name varchar(50)
);
CREATE TABLE #ParameterValue
(
pID int,
smonth varchar(50),
value varchar(50));
INSERT INTO #Trade
SELECT 1, 'stock', 1
UNION
SELECT 2, 'stock', 2
UNION
SELECT 3, 'cert', 3
INSERT INTO #Parameter
SELECT 1,1,'amount'
UNION
SELECT 2,1,'price'
UNION
SELECT 3,2,'amount'
UNION
SELECT 4,2,'price'
UNION
SELECT 5,3,'amount'
UNION
SELECT 6,3,'price'
INSERT INTO #ParameterValue
SELECT 1,1,'5'
UNION
SELECT 2,1,'500'
UNION
SELECT 3,1,'15'
UNION
SELECT 4,1,'300'
UNION
SELECT 5,1,'5'
UNION
SELECT 5,2,'10'
UNION
SELECT 5,3,'5'
UNION
SELECT 6,1,'100'
UNION
SELECT 6,2,'200'
UNION
SELECT 6,3,'300'
/***/
-- Perform select
/***/
SELECT t.tID, paraval.smonth, MAX(case when para.name = 'amount' then paraval.value else null end)as amount, MAX(case when para.name = 'price' then paraval.value else null end) as price, max(T.position) as position
FROM #Trade T
INNER JOIN #Parameter para on T.tID=para.tID
INNER JOIN #ParameterValue paraval on para.pID=paraval.pID
Group by T.tId, paraval.smonth
/***/
DROP TABLE #Trade
DROP TABLE #Parameter
DROP TABLE #ParameterValue
RESULT :
tID smonth amount price position
1 1 5 500 1
2 1 15 300 2
3 1 5 100 3
3 2 10 200 3
3 3 5 300 3

How to add scope_identity() to UNION ALL syntax in SQL Server

I have a query for multiple inserts using UNION ALL.
How do I use SELECT scope_identity(); for each row of data inserted?
INSERT INTO MyTable (FirstCol, SecondCol)
SELECT 'First', 1
UNION ALL
SELECT 'Second', 2
UNION ALL
SELECT 'Third', 3
UNION ALL
SELECT 'Fourth', 4
UNION ALL
SELECT 'Fifth', 5
The short answer is no you can't. SCOPE_IDENTITY will give you the value of the last insert only. But you can use the OUTPUT clause from 2005 onwards. See https://msdn.microsoft.com/en-us/library/ms177564.aspx for information on how to use this clause.
You can use OUTPUT Clause to get Multiple Identity Column Value instead of scope_identity() while inserting Multiple Row.
Create Table tablename
(id int identity(1,5) Primary KEY, b int , c int)
DECLARE #tempIDs TABLE (id int)
INSERT tablename (b, c)
OUTPUT inserted.id INTO #tempIDs
SELECT 1, 1
UNION ALL
SELECT 2, 2
UNION ALL
SELECT 200, 3
UNION ALL
SELECT 3000, 4
UNION ALL
SELECT 400, 5
Select * from #tempIDs
Now your table variable #tempIDs have All Primary Key Data those are inserted using UNION ALL.

Compare one column values for the table in sql

I have table with X number of columns. One of them is nvarchar(50). Values of this column are like this:
13-46187(IC)
13-46186(IC)
13-46189
13-46185
13-46184
I want to extract/find the highest number that the column value ends with (in this case 189). How do I accomplish that?
This is hardcoded stuff. but will give you some ideas..
create table #temp
(
textfield varchar(50)
)
insert into #temp
select '13-46187(IC)'
UNION
select '13-46186(IC)'
UNION
select '13-46189'
UNION
select '13-46185'
UNION
select '13-46184'
select Max(Convert(int,substring(SUBSTRING(textfield, 6, LEN(textfield)), 1, 3)))
from #temp