Insert with select for multiple records - sql

I have an insert statements for which I want to make 2 inserts. I have the following code:
INSERT INTO [dbo].[Licemb]
([Lic_Id],
[LicEmb_EmbTS],
[LicEmb_EmbOffset])
SELECT TOP 1
Lic_ID,
'00:00:00',
-7
FROM dbo.Lics
WHERE Org_ID = 2
ORDER BY NP_ID DESC
UNION ALL
SELECT TOP 1
Lic_ID,
'00:00:00',
-7
FROM dbo.Lics
WHERE Org_ID = 4
ORDER BY NP_ID DESC
however I keep getting syntax errors and I can't find a work around after searching for a while.
Error:
Incorrect syntax near the keyword 'UNION'.
How can I modify this code so that I can use a single statement to make 2 inserts with selects?
Any help would be much appreciated.

you can only have one order by for your entire union statement.
if you need to order each select you will need to run a sub query and union them
so
INSERT INTO [dbo].[Licemb]
([Lic_Id],
[LicEmb_EmbTS],
[LicEmb_EmbOffset])
select id,daytime,embargo from (
SELECT TOP 1
Lic_ID AS id,
'00:00:00' AS daytime,
-7 AS embargo
FROM [NLASQL].dbo.Lics
WHERE Org_ID = 2
ORDER BY NP_ID DESC)
UNION ALL
select id,daytime,embargo from (
SELECT TOP 1
Lic_ID AS id,
'00:00:00' AS daytime,
-7 AS embargo
FROM [NLASQL].dbo.Lics
WHERE Org_ID = 4
ORDER BY NP_ID DESC)
this is not an ideal solution and would ask why you need to order each set of data and then approach the problem from that angle.

If you use a union (all), there can only be one order by, namely after the last unioned query. This order by is applied over all queries in the union.

Related

Conditional Order By in sql

I have a sample data, which I want to sort. If User is 1,then sort views in descending, otherwise if User is not 1,then sort normally.
I have written below sql,and I am getting required result.
My Question is Why and How it works?
with data as (
select 2 as User, 1 as Views UNION ALL
select 1,3 UNION ALL
select 4,1 UNION ALL
select 1,5 UNION ALL
select 1,6 UNION ALL
select 2,6 UNION ALL
select 7,2 UNION ALL
select 8,3 UNION ALL
select 3,9
)
select ARRAY_AGG(struct(User,Views) order by if(User=1,1,0) desc ,Views desc )
from data
I am confused with if(User=1,1,0), if User=1,then 1.Is this 1,the
column number? If its column number,then ,when User is not equal to
1,then the value will be 0 ,which is not any column.
I was researching on this,and found that,if I write, if(User=1,100,0) desc ,Views desc ,then also I am getting correct result ,mean numbers in that IF() are not columns, otherwise 100 will produce error ,becoz there is no 100th column.
Can Anyone explain me,how its working?
Image 1
Image 2
Can Anyone explain me,how its working?
I think below is the simplest way to explain/show what is happening here
Consider below slightly modified/simplified example - I eliminated aggregation to focus on ordering aspect only
with data as (
select 2 as user, 1 as views union all
select 1,3 union all
select 4,1 union all
select 1,5 union all
select 1,6 union all
select 2,6 union all
select 7,2 union all
select 8,3 union all
select 3,9
)
select *, if(user=1,1,0) sort
from data
order by sort desc, views desc
output of above is
I don't think you have any doubts why above result is as is - it is just straightforward!!
Now - if you use if(user=1,100,0) - you get
Obviously, exactly same output (in terms of ordering) and I still don't think you have any doubts why it is as it is
So, finally to streamline query - users (or at least power users) would use the shortcut - instead of introducing sort column to use in order by - they would move this into order by itself
Hope this is clear now for you!

Insert duplicate row in SQL Server view

I was wondering if it was possible in SQL Server 2008 R2 to create a view with only the last column (DateTime DESC), but this last row should be copied in the view again.
So the end result would be a View with two rows with the same data.
The query to select one row is easy:
SELECT TOP 1 *
FROM Reporting
ORDER BY DateTime DESC
or
SELECT TOP 1 *
FROM Reporting
WHERE DateTime IN (SELECT MAX(DateTime)
FROM Reporting)
This returns only one row, but I want to duplicate this row in the view again.
Thanks
The syntax in the above answer is invalid. You are not allowed to have ORDER BY in each data source in the UNION ALL. You can have only one at the final statement. So, this is wrong:
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
UNION ALL
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
And should be done like this:
SELECT * FROM (SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC)
UNION ALL
SELECT * FROM (SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC);
I will advice using a different approach. Use fake data source and then cross apply.
SELECT SI.*
FROM
(
SELECT 1
UNION ALL
SELECT 2
) DS ([col])
CROSS APPLY
(
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
) SI;
You can test easily that the execution plan of this statement is better causing only one ordering and index scan:
Try Union all:
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC
UNION ALL
SELECT TOP 1 * FROM Reporting ORDER BY DateTime DESC

How to do union all with different order by conditions

I have a table with data like
I want all the records from the table but which the record having EnquiryStatus=1 and order by LastAttendendedDate should come on the top and remaining records should come after those records. I tried to select twice with where condition and tried to union all them, But with that union all not allowing me to order by on different ways. I can do it in c# by retriving the data as two table and merge them as single. But I want it in sql..
EDITS:
I want something like
Select * From EnquiryMaster A Where A.BranchID=16 and EnquiryStatus=1 ORDER BY A.CreatedDate Desc
UNION ALL
Select * From EnquiryMaster A Where A.BranchID=16 and EnquiryStatus in(0,2,3) ORDER BY EnquiryStatus,A.CreatedDate Desc
SELECT * FROM TABLE_NAME WHERE ORDER BY CASE WHEN EnquiryStatus='1' THEN LastAttendendedDate END DESC
You can use this in sql.
Try this
select * from your_table
order by case when EnquiryStatus=1 then LastAttendendedDate end DESC

SQL Server : UNION ALL but remove duplicate IDs by choosing first date of occurrence

I am unioning two queries but I'm getting an ID that occurs in each query. I do not know how to keep only the first time the id occurs. Everything else about the row is different. In general, it will be hard to know which of the two queries I will have to keep a duplicate on, therefore, I need a general solution.
I was thinking about creating a temp table and choosing the min date (once the date has been converted to an int).
Any ideas on the proper syntax?
You can do this using the row_number() function. This will assign a sequential number, starting with 1, to each row with the same id (based on the partition by clause). The ordering of the sequence is determined by the order by clause. So, the following assigns 1 to the earliest date for each id:
select t.*
from (select t.*,
row_number() over (partition by id order by date asc) as seqnum
from ((select *
from <subquery1>
) union all
(select *
from <subquery2>
)
) t
) t
where seqnum = 1;
The final where clause simply filters for the first occurrence.
If you use the keyword UNION, then it will remove duplicates from the two data sets you are working with. UNION ALL preserves duplicates.
You can view the specifics here:
http://www.w3schools.com/sql/sql_union.asp
If you want to only have one of the 2 records and they are not identical you will have to filter them yourself. You may need to do something like the following. THis may be possible to do with the one (select union select) block but this should get you started.
select *
from (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x1
, (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x2
where x1.id = x2.id
and x1.date < x2.date
Although rethinking this if you go down a path like this why bother to UNION it?

recursively increment a date in sql

I am working on a historical conversion of data and was wondering if there's a more efficient way to accomplish a date increment.
I receive a data from a source system on a saturday date (1-7-13) and would like to push that data to make it fill all days of the previous week (1-6-13,1-5-13 ect).
So currently i am doing several unions
insert into target
(date, name)
select date,name
from
(
SELECT date as date, name FROM SOURCE
UNION
SELECT date - 1 as date, name FROM SOURCE
UNION
SELECT date -2 as date, name FROM SOURCE
)
I only ask because it looks like close to 500 million records are going to be going though this sql script. Incase it matters it is going to be running in a BTEQ script in TERADATA.
First, your code would be faster using union all rather than union. union removes duplicates, which does not seem to be needed in this case. If you do need them removed, then do it at the source level:
from (select distinct name from source)
Rather than doing it implicitly with union.
You can also try a cross join approach:
select date - i, name
from source cross join
(select 0 as i union all select 1 union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6
) const
This might be a bit faster, because it doesn't need to set up the reads to the table multiple times.
One option is to use a recursive query, but I don't think it would be much faster -- just perhaps easier to read:
WITH RECURSIVE recursiveCTE (date, name) AS (
SELECT date, name
FROM Source
UNION ALL
SELECT r.date-1, r.name
FROM recursiveCTE R
JOIN Source T ON R.name = T.name AND T.date < r.date+6
)
INSERT INTO Target (date,name)
SELECT date,name From recursiveCTE