Lets say I have a table with following columns:
Id,TableName,Columnname
Normally If I would like to do a select with ordering on TableName Primary and ColumnName secondary I would do
Select * From MyTable Order By TableName,ColumnName
Now say I would like a special case of ordering depending on TableName
Select * From MyTable Order By Case
When TableName = 'Foo' Then '1'
When TableName = 'Bar' Then '2'
When TableName = 'Test' Then '3'
ELSE 1000 END;
How do I combine the second alternative with the first alternative, that is special ordering on first TableName and then order the Columnnames with that TableName?
I'm running Microsoft SQL
Thanks in advance.
Just add column in order list, like any other ORDER BY :)
Select * From MyTable Order By Case
When TableName = 'Foo' Then '1'
When TableName = 'Bar' Then '2'
When TableName = 'Test' Then '3'
ELSE 1000 END, ColumnName;
The case method is fine. I would often use this short-cut:
Select *
From MyTable
Order By charindex(TableName, ',Test,Bar,Foo,') desc
This is a wee bit arcane. charindex() returns the position of the name in the string. So, this form will not work for all string values, but it can be generalized:
Order By charindex(',' + TableName + ',', ',Test,Bar,Foo,') desc
The reversal of the list is to handle missing values. These are assigned a value of 0, so by putting the values in reverse order, the missing ones come last. Note that if I know all the values, then I would write this as:
Order By charindex(TableName, ',Foo,Bar,Test,') asc
As alternative, you could
1) create a new table
CREATE TABLE_ORDER (TABLE_NAME VARCHAR(100) NOT NULL, ORDER_VAL INT);
ALTER TABLE TABLE_ORDER ADD CONSTRAINT TABLE_ORDER_PK PRIMARY KEY(TABLE_NAME);
2) insert into it appropriate values:
INSERT INTO TABLE_ORDER (TABLE_NAME, ORDER_VAL) VALUES ('Foo', 1);
INSERT INTO TABLE_ORDER (TABLE_NAME, ORDER_VAL) VALUES ('Bar', 2);
INSERT INTO TABLE_ORDER (TABLE_NAME, ORDER_VAL) VALUES ('Test', 3);
3) Use the following query
SELECT A.*
FROM MYTABLE A
LEFT JOIN TABLE_ORDER B ON A.TABLENAME= B.TABLE_NAME
ORDER BY B.ORDER_VAL, A.COLUMNNAME
Related
I'm new in SQL. I'm trying to insert data into a SQL table. If I insert for the first time it works but if I try to do a new insert I get the error
Violation of UNIQUE KEY constraint.
The unique key constraint is on (uc, start_date). The error occurs because there is already the record (-1, 1900-01-01) in the table. Here is my code:
insert into tableA ([start_date],[end_date],[uc],[desc],[ind_sus])
select '1900-01-01' [start_date]
,'9999-12-31'[end_date]
,case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end [uc]
,'' [desc]
,0 [ind_sus]
from tableB b
where right([DIM], 2) NOT IN (select uc from tableA a
where a.uc = right([DIM], 2)
and convert(date,b.[DATETRIAL]) between a.start_date and a.end_date)
group by case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end
The data that I'm trying to insert fulfills the when condition of the case and therefore another (-1, 1900-01-01) as key. I tried:
case when not exists(select uc from tableA where uc = '-1') then '-1'
to insert only if the data doesn't exist. It didn't work because I have to put the same code in the group by clause and I realized that I cannot do a subquery in the group by clause. So, is there a way to check at the case clause level if a value already exist before inserting? Or should I rewrite the request in another way? Database can't be modified
I need suggestions please.
In order to be able to check and insert data when not exists you need to use MERGE operator (see docs for more info).
Since you did not provide us with test data, I'm not sure I can easily update your query, so here is an example I made up to show you how to do things you need using MERGE.
Create table and insert 1 row with id = 1:
create table some_table(id int primary key, text_col varchar(10));
insert into some_table values(1, 'first');
Try to insert a line with same id
insert into some_table values(1, 'another first'); -- it fails of course
same thing using merge
merge into some_table -- target table
using
(select 1 id, 'another first' text_col) new_data -- source data
on some_table.id = new_data.id -- column to check on
when not matched then
insert (id, text_col) values(new_data.id, new_data.text_col);
I hope this helps
My try to change your query to merge would be like that
(keep in mind I did not tested it so fixing syntax or possible data errors is up to you)
merge into tableA a
using (select uc
,'1900-01-01' [start_date]
,'9999-12-31'[end_date]
,case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2) end [uc]
,'' [desc]
,0 [ind_sus]
from tableB b
group by case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end) b
on a.right([DIM], 2) = b.uc
and convert(date,b.[DATETRIAL]) between a.start_date and a.end_date
when not matched then
insert([start_date],[end_date],[uc],[desc],[ind_sus])
values(b.start_date, b.end_date, b.uc, b.desc, b.ind_sus)
Table1
Id bigint primary key identity(1,1)
Status nvarchar(20)
Insert dummy data
Insert into Table1 values ('Open') --1
Insert into Table1 values ('Open') --2
Insert into Table1 values ('Grabbed') --3
Insert into Table1 values ('Closed') --4
Insert into Table1 values ('Closed') --5
Insert into Table1 values ('Open') --6
How would I construct a single select statement which orders the data where records with 'Grabbed' status is first, followed by 'Closed', followed by 'Open' in SQL Server
Output:
Id Status
3 Grabbed
4 Closed
5 Closed
1 Open
2 Open
6 Open
I think you need something like this:
select *
from yourTable
order by case when Status = 'Grabbed' then 1
when Status = 'Closed' then 2
when Status = 'Open' then 3
else 4 end
, Id;
[SQL Fiddle Demo]
Another way is to using CTE like this:
;with cte as (
select 'Grabbed' [Status], 1 [order]
union all select 'Closed', 2
union all select 'Open', 3
)
select t.*
from yourTable t
left join cte
on t.[Status] = cte.[Status]
order by cte.[order], Id;
[SQL Fiddle Demo]
This could be done much better with a properly normalized design:
Do not store your Status as a textual content. Just imagine a typo (a row with Grabed)...
Further more a lookup table allows you to add side data, e.g. a sort order.
CREATE TABLE StatusLookUp(StatusID INT IDENTITY PRIMARY KEY /*you should name your constraints!*/
,StatusName VARCHAR(100) NOT NULL
,SortRank INT NOT NULL)
INSERT INTO StatusLookUp VALUES
('Open',99) --ID=1
,('Closed',50)--ID=2
,('Grabbed',10)--ID=3
CREATE TABLE Table1(Id bigint primary key identity(1,1) /*you should name your constraints!*/
,StatusID INT FOREIGN KEY REFERENCES StatusLookUp(StatusID));
Insert into Table1 values (1) --1
Insert into Table1 values (1) --2
Insert into Table1 values (3) --3
Insert into Table1 values (2) --4
Insert into Table1 values (2) --5
Insert into Table1 values (1) --6
SELECT *
FROM Table1 AS t1
INNER JOIN StatusLookUp AS s ON t1.StatusID=s.StatusID
ORDER BY s.SortRank;
I find that the simplest method uses a string:
order by charindex(status, 'Grabbed,Closed,Open')
or:
order by charindex(',' + status + ',', ',Grabbed,Closed,Open,')
If you are going to put values in the query, I think the easiest way uses values():
select t1.*
from t1 left join
(values ('Grabbed', 1), ('Closed', 2), ('Open', 3)) v(status, priority)
on t1.status = v.status
order by coalesce(v.priority, 4);
Finally. This need suggests that you should have a reference table for statuses. Rather than putting the string name in other tables, put an id. The reference table can have the priority as well as other information.
Try this:
select Id,status from tablename where status='Grabbed'
union
select Id,status from tablename where status='Closed'
union
select Id,status from tablename where status='Open'
I'm trying to insert some data to a table contains two things : "a string" and "maximum number in Order column + 1".
This is my query:
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' , (Max([Order]) + 1)
FROM MyTable
What is going wrong with my query?
I'm using Microsoft SQL Server 2005 SP3.
You can test this query like this:
I don't receive error:
create table #MyTable
(
[Text] varchar(40),
[Order] int NOT NULL
)
INSERT INTO #MyTable([Text],[Order])
SELECT 'MyText' [Text], isnull(max([order]) + 1, 0) [Order]
FROM #MyTable
drop table #MyTable
Original:
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' [Text], max([Order]) + 1 [Order]
FROM MyTable
or
INSERT INTO MyTable ([Text],[Order])
SELECT top 1 'MyText' [Text], max([Order]) + 1 [Order]
FROM MyTable
limit is not valid in SQL Server as far as I know.
Cannot insert the value NULL into column 'Order', table 'master.dbo.MyTable'; column does not allow nulls. INSERT fails. The statement has been terminated.
This means that the Order column isn't allowed to be null, and that the Max([Order]) + 1 part of your column returns NULL.
This is because your table is empty, as you already noticed by yourself.
You can work around this by replacing NULL by a real number in the query, using ISNULL():
INSERT INTO MyTable ([Text],[Order])
SELECT 'MyText' , (isnull(Max([Order]),0) + 1)
FROM MyTable
Unless he has a column named OrderBy
then he would have to add / assign all values within that Insert especially if the column does not allow for nulls
sounds like fully qualifying the Insert with the dbo.MyTable.Field may make more sense.
also why are you naming fields with SQL Key words...???
INSERT INTO MyTable ([Text],[Order] Values('MyTextTest',1)
try a test insert first..
I am trying to select some fields from one table and insert them into an existing table from a stored procedure. Here is what I am trying:
SELECT col1, col2
INTO dbo.TableTwo
FROM dbo.TableOne
WHERE col3 LIKE #search_key
I think SELECT ... INTO ... is for temporary tables which is why I get an error that dbo.TableTwo already exists.
How can I insert multiple rows from dbo.TableOne into dbo.TableTwo?
SELECT ... INTO ... only works if the table specified in the INTO clause does not exist - otherwise, you have to use:
INSERT INTO dbo.TABLETWO
SELECT col1, col2
FROM dbo.TABLEONE
WHERE col3 LIKE #search_key
This assumes there's only two columns in dbo.TABLETWO - you need to specify the columns otherwise:
INSERT INTO dbo.TABLETWO
(col1, col2)
SELECT col1, col2
FROM dbo.TABLEONE
WHERE col3 LIKE #search_key
There are two different ways to implement inserting data from one table to another table.
For Existing Table - INSERT INTO SELECT
This method is used when the table is already created in the database earlier and the data is to be inserted into this table from another table. If columns listed in insert clause and select clause are same, they are not required to list them. It is good practice to always list them for readability and scalability purpose.
----Create testable
CREATE TABLE TestTable (FirstName VARCHAR(100), LastName VARCHAR(100))
----INSERT INTO TestTable using SELECT
INSERT INTO TestTable (FirstName, LastName)
SELECT FirstName, LastName
FROM Person.Contact
WHERE EmailPromotion = 2
----Verify that Data in TestTable
SELECT FirstName, LastName
FROM TestTable
----Clean Up Database
DROP TABLE TestTable
For Non-Existing Table - SELECT INTO
This method is used when the table is not created earlier and needs to be created when data from one table is to be inserted into the newly created table from another table. The new table is created with the same data types as selected columns.
----Create a new table and insert into table using SELECT INSERT
SELECT FirstName, LastName
INTO TestTable
FROM Person.Contact
WHERE EmailPromotion = 2
----Verify that Data in TestTable
SELECT FirstName, LastName
FROM TestTable
----Clean Up Database
DROP TABLE TestTable
Ref 1 2
It would work as given below :
insert into Gengl_Del Select Tdate,DocNo,Book,GlCode,OpGlcode,Amt,Narration
from Gengl where BOOK='" & lblBook.Caption & "' AND DocNO=" & txtVno.Text & ""
If the destination table does exist but you don't want to specify column names:
DECLARE #COLUMN_LIST NVARCHAR(MAX);
DECLARE #SQL_INSERT NVARCHAR(MAX);
SET #COLUMN_LIST = (SELECT DISTINCT
SUBSTRING(
(
SELECT ', table1.' + SYSCOL1.name AS [text()]
FROM sys.columns SYSCOL1
WHERE SYSCOL1.object_id = SYSCOL2.object_id and SYSCOL1.is_identity <> 1
ORDER BY SYSCOL1.object_id
FOR XML PATH ('')
), 2, 1000)
FROM
sys.columns SYSCOL2
WHERE
SYSCOL2.object_id = object_id('dbo.TableOne') )
SET #SQL_INSERT = 'INSERT INTO dbo.TableTwo SELECT ' + #COLUMN_LIST + ' FROM dbo.TableOne table1 WHERE col3 LIKE ' + #search_key
EXEC sp_executesql #SQL_INSERT
select *
into existing table database..existingtable
from database..othertables....
If you have used select * into tablename from other tablenames already, next time, to append, you say select * into existing table tablename from other tablenames
IF you want a identity column in new table created with select into then it can be done as below.
SELECT
ID = IDENTITY(INT, 1, 1),
name
INTO table2
FROM table1
If you want to insert into Table_A, from Table_B, only if the column is not in Table_A, then use the following:
BEGIN TRANSACTION
INSERT INTO dbo.Table_A (Column_1)
SELECT DISTINCT Some_Column AS Column_1
FROM dbo.Table_B
WHERE Some_Column
NOT IN (SELECT DISTINCT GroupId
FROM dbo.Table_A)
COMMIT
I have
SELECT * FROM Table1 WHERE Col1 IN(4,2,6)
I want to select and return the records with the specified order which i indicate in the IN clause
(first display record with Col1=4, Col1=2, ...)
I can use
SELECT * FROM Table1 WHERE Col1 = 4
UNION ALL
SELECT * FROM Table1 WHERE Col1 = 6 , .....
but I don't want to use that, cause I want to use it as a stored procedure and not auto generated.
I know it's a bit late but the best way would be
SELECT *
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')
Or
SELECT CHARINDEX(CAST(Col1 AS VARCHAR), '4,2,67')s_order,
*
FROM Table1
WHERE Col1 IN( 4, 2, 6 )
ORDER BY s_order
You have a couple of options. Simplest may be to put the IN parameters (they are parameters, right) in a separate table in the order you receive them, and ORDER BY that table.
The solution is along this line:
SELECT * FROM Table1
WHERE Col1 IN(4,2,6)
ORDER BY
CASE Col1
WHEN 4 THEN 1
WHEN 2 THEN 2
WHEN 6 THEN 3
END
select top 0 0 'in', 0 'order' into #i
insert into #i values(4,1)
insert into #i values(2,2)
insert into #i values(6,3)
select t.* from Table1 t inner join #i i on t.[in]=t.[col1] order by i.[order]
Replace the IN values with a table, including a column for sort order to used in the query (and be sure to expose the sort order to the calling application):
WITH OtherTable (Col1, sort_seq)
AS
(
SELECT Col1, sort_seq
FROM (
VALUES (4, 1),
(2, 2),
(6, 3)
) AS OtherTable (Col1, sort_seq)
)
SELECT T1.Col1, O1.sort_seq
FROM Table1 AS T1
INNER JOIN OtherTable AS O1
ON T1.Col1 = O1.Col1
ORDER
BY sort_seq;
In your stored proc, rather than a CTE, split the values into table (a scratch base table, temp table, function that returns a table, etc) with the sort column populated as appropriate.
I have found another solution. It's similar to the answer from onedaywhen, but it's a little shorter.
SELECT sort.n, Table1.Col1
FROM (VALUES (4), (2), (6)) AS sort(n)
JOIN Table1
ON Table1.Col1 = sort.n
I am thinking about this problem two different ways because I can't decide if this is a programming problem or a data architecture problem. Check out the code below incorporating "famous" TV animals. Let's say that we are tracking dolphins, horses, bears, dogs and orangutans. We want to return only the horses, bears, and dogs in our query and we want bears to sort ahead of horses to sort ahead of dogs. I have a personal preference to look at this as an architecture problem, but can wrap my head around looking at it as a programming problem. Let me know if you have questions.
CREATE TABLE #AnimalType (
AnimalTypeId INT NOT NULL PRIMARY KEY
, AnimalType VARCHAR(50) NOT NULL
, SortOrder INT NOT NULL)
INSERT INTO #AnimalType VALUES (1,'Dolphin',5)
INSERT INTO #AnimalType VALUES (2,'Horse',2)
INSERT INTO #AnimalType VALUES (3,'Bear',1)
INSERT INTO #AnimalType VALUES (4,'Dog',4)
INSERT INTO #AnimalType VALUES (5,'Orangutan',3)
CREATE TABLE #Actor (
ActorId INT NOT NULL PRIMARY KEY
, ActorName VARCHAR(50) NOT NULL
, AnimalTypeId INT NOT NULL)
INSERT INTO #Actor VALUES (1,'Benji',4)
INSERT INTO #Actor VALUES (2,'Lassie',4)
INSERT INTO #Actor VALUES (3,'Rin Tin Tin',4)
INSERT INTO #Actor VALUES (4,'Gentle Ben',3)
INSERT INTO #Actor VALUES (5,'Trigger',2)
INSERT INTO #Actor VALUES (6,'Flipper',1)
INSERT INTO #Actor VALUES (7,'CJ',5)
INSERT INTO #Actor VALUES (8,'Mr. Ed',2)
INSERT INTO #Actor VALUES (9,'Tiger',4)
/* If you believe this is a programming problem then this code works */
SELECT *
FROM #Actor a
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY case when a.AnimalTypeId = 3 then 1
when a.AnimalTypeId = 2 then 2
when a.AnimalTypeId = 4 then 3 end
/* If you believe that this is a data architecture problem then this code works */
SELECT *
FROM #Actor a
JOIN #AnimalType at ON a.AnimalTypeId = at.AnimalTypeId
WHERE a.AnimalTypeId IN (2,3,4)
ORDER BY at.SortOrder
DROP TABLE #Actor
DROP TABLE #AnimalType
ORDER BY CHARINDEX(','+convert(varchar,status)+',' ,
',rejected,active,submitted,approved,')
Just put a comma before and after a string in which you are finding the substring index or you can say that second parameter.
And first parameter of CHARINDEX is also surrounded by , (comma).