Simulate a table with multiple rows just with SELECT statement - sql

If I can do the following select statement to create a table with one value
SELECT 'myname' AS 'Name'
this will return a table with column = Name and one value = myname
how can I work around this to return one column with multiple values from just the select statement
I don't want to do this :
DECLARE #tmp TABLE (Name varchar(50))
INSERT INTO #tmp (Name) VALUES ('myname1'),('myname2')
SELECT * FROM #tmp
Just from a single SELECT statement if possible

Or, you can use the multiple VALUES in the SELECT, like:
SELECT [Name]
FROM (VALUES ('myname1'),('myname2')) AS X([name])

If you're wanting to simulate a table with multiple rows just with SELECT statement, this can typically be done with UNION of rows:
SELECT 'myname1' AS 'Name' UNION
SELECT 'myname2' UNION
SELECT 'myname3'
-- etc
Demo: http://www.sqlfiddle.com/#!3/d41d8/12433

In case you want to simulate sequential data like in your example.You can define a recursive CTE and use it like a table.
Below code will generate 10 records
;With Users as
(
Select 1 as ID, CAST('Username1' AS varchar(25)) as Name
union all
Select ID + 1 , CAST('Username'+CAST(ID+1 AS varchar(5) ) AS varchar(25))
from Users
where ID < 10
)
SELECT * FROM Users
Here is SQL Fiddle http://www.sqlfiddle.com/#!3/d41d8/12452
But CTE cannot be used in multiple statements.If you need to use it in multi statements. Then insert data from CTE to Temp Table or Table Variable.

Related

Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. - DECLARE to use SPLIT_ROW

I have that query:
DECLARE #test AS varchar =
(select * from users where Usr_ID in
(select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931))
And I've got an error "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS." The result of select statement are three numbers, which i need to split into three rows.
(select * from users where Usr_ID in
(select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931))
you query returns multiple rows as a result variable can not contain multiple rows value.
if your query just return one value then it will return correct result
but if you change your query like below then it will works
DECLARE #test AS varchar =
(select top 1 Doc_Shortstringcolumn1 from users where Usr_ID in
(select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931)
)
Looking at your Query, It seems that you are trying to store a table into a variable which is of Varchar data type which you cannot do in SQL Server.
There are 2 possible solutions
1.
You May select only the Required filed instead of the * ad in that case if there are more than one row is returned, then only the first one will be stored in the variable and all other values will be ignored.
If this is ok with you then you may go ahead with this approach
DECLARE #test AS varchar =
select
#test = YourColumnName
from users where Usr_ID in
(
select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931
)
2
The Second approach is to use a table variable or a Temporary table to store the values so that you can store all the values and retrieve the same when needed.
Using Temp Table
select
*
into #temp
from users where Usr_ID in
(
select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931
)
using Table Variable
DECLARE #test AS TABLE
(
Column1 VARCHAR(50),
Column2 VARCHAR(50),
Column3 VARCHAR(50)
)
INSERT INTO #Test
(
Column1,
Column2,
Column3
)
select
YourColumnName1,
YourColumnName2,
YourColumnName3
from users where Usr_ID in
(
select Doc_Shortstringcolumn1 from Documents where Doc_ID = 11931
)

Add empty rows to results

I want to add empty rows to results fetched from a select statement. For example, if the select query fetch 4 rows then 2 empty rows needs to be fetched. Objective should be the number of rows fetched should be 6 every time. The number of rows fetched will be 6 maximum if there are 6 rows with data.
Any idea?
In SQL-SERVER You can create temp table to update It with empty rows and you can use WHILE to insert desired number of rows with empty values. Something like:
-- Create temp table to update data with empty rows
CREATE TABLE #HoldEmptyRows
(
Id NVARCHAR(20),
CustomerName NVARCHAR(20),
CustomerEmail NVARCHAR(20)
)
-- Insert data from SourceTable to temp
INSERT INTO #HoldEmptyRows
SELECT * FROM SourceTable
-- Do while count from temp table < of desired number insert empty rows
WHILE ((SELECT COUNT(*) cnt FROM #HoldEmptyRows) < 6)
BEGIN
INSERT INTO #HoldEmptyRows VALUES ('', '', '')
END
SELECT * FROM #HoldEmptyRows
DEMO AT SQL FIDDLE
Try the below logic:
with cte as
(
select 0 as col1
union all
select col1+1 from cte where cte.col1<10
)
select * into #temp1 from cte
create table #test
(rownum int,col1 varchar(100))
declare #i int=1
while (#i<=6)
begin
insert into #test
select * from
(select row_Number() over (order by (Select 0))rownum, * from #temp1)x
where rownum=#i
Set #i=#i+1
end
select case when rownum>4 then '' else col1 end as col1 from #test

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

SELECT * INTO retains ORDER BY in SQL Server 2008 but not 2012

Execute the following SQL in 2008 and 2012. When executed in 2008, the returned result is in its correct sort order. In 2012, the sortorder is not retained.
Is this a known change? Is there a work-around for 2012 to retain the sort order?
CREATE TABLE #MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO #MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4
SELECT * INTO #Result FROM #MyTable ORDER BY SortOrder
SELECT * FROM #Result
DROP TABLE #MyTable
DROP TABLE #Result
How can you tell what the order is inside a table by using select * from #result? There is no guarantee as to the order in a select query.
However, the results are different on SQL Fiddle. If you want to guarantee that the results are the same, then add a primary key. Then the insertion order is guaranteed:
CREATE TABLE MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4
select top 0 * into result from MyTable;
alter table Result add id int identity(1, 1) primary key;
insert into Result(name, sortorder)
SELECT * FROM MyTable
ORDER BY SortOrder;
I still abhor doing select * from Result after this. But yes, it does return them in the correct order in both SQL Server 2008 and 2012. Not only that, but because SQL Server guarantees that primary keys are inserted in the proper order, the records are even guaranteed to be in the correct order in this case.
BUT . . . just because the records are in a particular order on the pages doesn't mean they will be retrieved in that order with no order by clause.
When using ORDER BY with an INSERT, it has never been guaranteed to do anything other than control the order of the identity column if present.
Prior to SQL Server 2012, the optimizer always produced a plan as if an identity column existed and thus appears to order correctly. SQL Server 2012 correctly does not assume an identity column exists, and only orders if the table actually has an identity column.
So you can resolve this issue by adding an Identity column to your temp result table.
However, you really should just add an ORDER BY clause to your SELECT statement? SELECT statements without an ORDER BY have never been guaranteed to return the results in any specific order. Always add the ORDER BY clause to ensure you receive the results the way you expect.
First, thanks sgeddes for the explanation, it helped a lot.
The thing about defining a table variable or creating a temp table is you have to define it, and if you are going to go through the work of defining it, you might as well do the insert the correct way:
INSERT INTO #Result (col1, col2...)
SELECT Col1, Col2... FROM #MyTable....
In my case, the ORDER BY in the INSERT was dynamic so when I called "SELECT * FROM #Result", the ORDER BY was unknown. My solution was to add a ROW_NUMBER column that I could hardcode into the SELECT when I was getting the data.
Yea, I still have to include an ORDER BY, but at least it's static. Here's what I did:
--Insert
SELECT ROW_NUMBER() OVER (ORDER BY T.SortOrder ASC) AS RowNum, T.*
INTO #Result
FROM (SELECT * FROM #MyTable ...) AS T;
--Get data out
SELECT * FROM #Result ORDER BY RowNum;
Hope this helps.
Workaround :
You could add a SET ROWCOUNT before this type of query, then put if back to zero after to reset it, it works. This will force SQL to keep the order in your query.
SET ROWCOUNT 1000000000
CREATE TABLE #MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO #MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4
SELECT * INTO #Result FROM #MyTable ORDER BY SortOrder
SELECT * FROM #Result
SET ROWCOUNT 0
DROP TABLE #MyTable
DROP TABLE #Result
If you have different sorted results when querying each database, your collation is probably different between the two.
Try explicitly setting the collation in your query and see if your results are returned in the same order in both databases, e.g.
SELECT * FROM #Result ORDER BY C1 COLLATE Latin1_General_CS_AS
You must to create ROW_NUMBER() order by column you want to order. Order by directly in the select, is ignored when insert is executed.
CREATE TABLE #MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO #MyTable
SELECT 'b', 2
UNION ALL SELECT 'c', 3
UNION ALL SELECT 'a', 1
UNION ALL SELECT 'e', 5
UNION ALL SELECT 'd', 4
SELECT Name,
ROW_NUMBER() OVER (ORDER BY MyTable.SortOrder) AS SortOrder
INTO #Result
FROM #MyTable AS MyTable
ORDER BY SortOrder
SELECT * FROM #Result
DROP TABLE #MyTable
DROP TABLE #Result

how to change this sql query

SELECT *
FROM dbo.tbh_table
WHERE TopicID IN (
SELECT value
FROM dbo.fn_split('19,',')
)
I have to change above query to execute result like below
SELECT *
FROM dbo.tbh_table
WHERE TopicID LIKE '%19,%'
My topicID values are like this 15,19,12,1
But split will give values are 15 19 12 1. because of which i am not able to execute the query.
any guidance will help
Assuming that fn_split is a table valued function (TVF), returning a TABLE (value INT), use this:
SELECT t.*
FROM dbo.tbh_table t
CROSS APPLY
dbo.fn_split(TopicID) split
WHERE split.value = 19
You could add your IDs to a table variable and then join with the table variable to determine if TopicID was in the table variable.
DECLARE #DesiredIDs TABLE (
DesiredID INT
)
INSERT INTO #DesiredIDs (DesiredID) Values (15)
INSERT INTO #DesiredIDs (DesiredID) Values (19)
INSERT INTO #DesiredIDs (DesiredID) Values (12)
INSERT INTO #DesiredIDs (DesiredID) Values (1)
select * from tbh_table t
left join #DesiredIDs d on d.DesiredID = t.TopicID
where d.DesiredID is not null
If I understand your question correctly, you want something like this:
SELECT *
FROM dbo.tbh_table
WHERE 19 IN (
SELECT value
FROM dbo.fn_split(TopicId,',')
)