INSERTing results FROM table USING CTE - sql

I'm trying to insert values from a Table using CTE but something doesn't work. I suppose that CTE doesn't work in this way?
Can anyone explain to me what's wrong here and suggest me an alternative, or correct my Query if I'm missing something?
WITH t1 AS( SELECT id_sitio as id_sitio FROM Sitio WHERE nombre = 'Insert your site name here')
INSERT INTO Sitio_tipo_equipo (id_sitio, id_tipo_equipo)
VALUES
(t1.id_sitio ,4),
(t1.id_sitio, 6),
(t1.id_sitio, 7),
(t1.id_sitio, 9);

I think this is your intention:
WITH t1 AS (
SELECT id_sitio
FROM Sitio
WHERE nombre = 'Insert your site name here'
)
INSERT INTO Sitio_tipo_equipo(id_sitio, id_tipo_equipo)
SELECT t1.id_sitio, n.n
FROM t1 CROSS JOIN
(SELECT 4 as n UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 9
) n
You wouldn't normally use a CTE with an insert . . . values statement.

With the information at hand...
INSERT INTO Sitio_tipo_equipo (id_sitio, id_tipo_equipo)
SELECT id_sitio,eq.id_tipo_equipo
FROM Sitio
CROSS APPLY (
SELECT 4 [id_tipo_equipo] UNION
SELECT 6 UNION
SELECT 7 UNION
SELECT 9
) eq
WHERE nombre = 'Insert your site name here'
What I would do if I can correctly guess your database structure:
INSERT INTO Sitio_tipo_equipo (id_sitio, id_tipo_equipo)
SELECT id_sitio,id_tipo_equipo
FROM Sitio
CROSS APPLY tipo_equipo
WHERE nombre = 'Insert your site name here'
AND id_tipo_equipo IN (4,6,7,9)

Related

Get every combination of sort order and value of a csv

If I have a string with numbers separated by commas, like this:
Declare #string varchar(20) = '123,456,789'
And would like to return every possible combination + sort order of the values by doing this:
Select Combination FROM dbo.GetAllCombinations(#string)
Which would in result return this:
123
456
789
123,456
456,123
123,789
789,123
456,789
789,456
123,456,789
123,789,456
456,789,123
456,123,789
789,456,123
789,123,456
As you can see not only is every combination returned, but also each combination+sort order as well. The example shows only 3 values separated by commas, but should parse any amount--Recursive.
The logic needed would be somewhere in the realm of using a WITH CUBE statement, but the problem with using WITH CUBE (in a table structure instead of CSV of course), is that it won't shuffle the order of the values 123,456 456,123 etc., and will only provide each combination, which is only half of the battle.
Currently I have no idea what to try. If someone can provide some assistance it would be appreciated.
I use a User Defined Table-valued Function called split_delimiter that takes 2 values: the #delimited_string and the #delimiter_type.
CREATE FUNCTION [dbo].[split_delimiter](#delimited_string VARCHAR(8000), #delimiter_type CHAR(1))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,cte100(num) AS
(
SELECT 1
FROM cte10 t1, cte10 t2
)
,cte10000(num) AS
(
SELECT 1
FROM cte100 t1, cte100 t2
)
,cte1(num) AS
(
SELECT TOP (ISNULL(DATALENGTH(#delimited_string),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
,cte2(num) AS
(
SELECT 1
UNION ALL
SELECT t.num+1
FROM cte1 t
WHERE SUBSTRING(#delimited_string,t.num,1) = #delimiter_type
)
,cte3(num,[len]) AS
(
SELECT t.num
,ISNULL(NULLIF(CHARINDEX(#delimiter_type,#delimited_string,t.num),0)-t.num,8000)
FROM cte2 t
)
SELECT delimited_item_num = ROW_NUMBER() OVER(ORDER BY t.num)
,delimited_value = SUBSTRING(#delimited_string, t.num, t.[len])
FROM cte3 t;
Using that I was able to parse the CSV to a table and join it back to itself multiple times and use WITH ROLLUP to get the permutations you are looking for.
WITH Numbers as
(
SELECT delimited_value
FROM dbo.split_delimiter('123,456,789',',')
)
SELECT CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR)
FROM Numbers as Nums1
LEFT JOIN Numbers as Nums2
ON Nums2.delimited_value not in (Nums1.delimited_value)
LEFT JOIN Numbers as Nums3
ON Nums3.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value)
LEFT JOIN Numbers as Nums4
ON Nums4.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value, Nums3.delimited_value)
GROUP BY CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR) WITH ROLLUP
If you will potentially have more than 3 or 4, you'll want to expand your code accordingly.

How do I combine 2 records with a single field into 1 row with 2 fields (Oracle 11g)?

Here's a sample data
record1: field1 = test2
record2: field1 = test3
The actual output I want is
record1: field1 = test2 | field2 = test3
I've looked around the net but can't find what I'm looking for. I can use a custom function to get it in this format but I'm trying to see if there's a way to make it work without resorting to that.
thanks a lot
You need to use pivot:
with t(id, d) as (
select 1, 'field1 = test2' from dual union all
select 2, 'field1 = test3' from dual
)
select *
from t
pivot (max (d) for id in (1, 2))
If you don't have the id field you can generate it, but you will have XML type:
with t(d) as (
select 'field1 = test2' from dual union all
select 'field1 = test3' from dual
), t1(id, d) as (
select ROW_NUMBER() OVER(ORDER BY d), d from t
)
select *
from t1
pivot xml (max (d) for id in (select id from t1))
There are several ways to approach this - google pivot rows to columns. Here is one set of answers: http://www.dba-oracle.com/t_converting_rows_columns.htm

Joining a list of values with table rows in SQL

Suppose I have a list of values, such as 1, 2, 3, 4, 5 and a table where some of those values exist in some column. Here is an example:
id name
1 Alice
3 Cindy
5 Elmore
6 Felix
I want to create a SELECT statement that will include all of the values from my list as well as the information from those rows that match the values, i.e., perform a LEFT OUTER JOIN between my list and the table, so the result would be like follows:
id name
1 Alice
2 (null)
3 Cindy
4 (null)
5 Elmore
How do I do that without creating a temp table or using multiple UNION operators?
If in Microsoft SQL Server 2008 or later, then you can use Table Value Constructor
Select v.valueId, m.name
From (values (1), (2), (3), (4), (5)) v(valueId)
left Join otherTable m
on m.id = v.valueId
Postgres also has this construction VALUES Lists:
SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS t (num,letter)
Also note the possible Common Table Expression syntax which can be handy to make joins:
WITH my_values(num, str) AS (
VALUES (1, 'one'), (2, 'two'), (3, 'three')
)
SELECT num, txt FROM my_values
With Oracle it's possible, though heavier From ASK TOM:
with id_list as (
select 10 id from dual union all
select 20 id from dual union all
select 25 id from dual union all
select 70 id from dual union all
select 90 id from dual
)
select * from id_list;
the following solution for oracle is adopted from this source. the basic idea is to exploit oracle's hierarchical queries. you have to specify a maximum length of the list (100 in the sample query below).
select d.lstid
, t.name
from (
select substr(
csv
, instr(csv,',',1,lev) + 1
, instr(csv,',',1,lev+1 )-instr(csv,',',1,lev)-1
) lstid
from (select ','||'1,2,3,4,5'||',' csv from dual)
, (select level lev from dual connect by level <= 100)
where lev <= length(csv)-length(replace(csv,','))-1
) d
left join test t on ( d.lstid = t.id )
;
check out this sql fiddle to see it work.
Bit late on this, but for Oracle you could do something like this to get a table of values:
SELECT rownum + 5 /*start*/ - 1 as myval
FROM dual
CONNECT BY LEVEL <= 100 /*end*/ - 5 /*start*/ + 1
... And then join that to your table:
SELECT *
FROM
(SELECT rownum + 1 /*start*/ - 1 myval
FROM dual
CONNECT BY LEVEL <= 5 /*end*/ - 1 /*start*/ + 1) mypseudotable
left outer join myothertable
on mypseudotable.myval = myothertable.correspondingval
Assuming myTable is the name of your table, following code should work.
;with x as
(
select top (select max(id) from [myTable]) number from [master]..spt_values
),
y as
(select row_number() over (order by x.number) as id
from x)
select y.id, t.name
from y left join myTable as t
on y.id = t.id;
Caution: This is SQL Server implementation.
fiddle
For getting sequential numbers as required for part of output (This method eliminates values to type for n numbers):
declare #site as int
set #site = 1
while #site<=200
begin
insert into ##table
values (#site)
set #site=#site+1
end
Final output[post above step]:
select * from ##table
select v.id,m.name from ##table as v
left outer join [source_table] m
on m.id=v.id
Suppose your table that has values 1,2,3,4,5 is named list_of_values, and suppose the table that contain some values but has the name column as some_values, you can do:
SELECT B.id,A.name
FROM [list_of_values] AS B
LEFT JOIN [some_values] AS A
ON B.ID = A.ID

SQL order by included character and string

I have a table and i want to colum joint_no column. The column's values are like these
FW-1
FW-2
.
.
.
FW-13
FW-R1
FW-1A
When i ordered them i get this results
FW-1
FW-10
FW-11
FW-12
FW-13
FW-1A
.
.
FW-R1
I want to get this result after sql query
FW-1
FW-1A
FW-2
FW-3
..
FW-13
FW-R1
can anybody help me?
If you can do it, I'd advise you to renumber the values so that the 'logical' order sticks to the alphabetical order. F-1 will then be updated to F-01, or F-001.
If you cannot do it, add a field that will be populated with the 'ordered' form of your code. You 'll then be able to order by the F-001 column and still display the F-1 value
Otherwise ordering your records will rapidly become your nightmare.
Using Patindex to find the first numeric expression as first sort field, then extracting the numeric part as integer as second sortfield and using the whole string as third sort field you might get the desired result.
Declare #a Table (c varchar(50))
Insert Into #a
Select 'FW-1'
Union Select 'FW-10'
Union Select 'FW-11'
Union Select 'FW-12'
Union Select 'FW-13'
Union Select 'FW-1A'
Union Select 'FW-2'
Union Select 'FW-3'
Union Select 'FW-R1'
Union Select 'FW-A1'
;With CTE as
(Select 1 as ID
Union All
Select ID + 1 from CTE where ID < 100
)
Select * from
(
Select c
,PATINDEX('%[0-9]%',c) as s1
,(Select Cast(
(Select Case
When SUBSTRING(c, ID, 1) LIKE '[0-9]'
Then SUBSTRING(c, ID, 1)
Else ''
End
From (Select * from CTE) AS X(ID)
Where ID <= LEN(c)
For XML PATH(''))
as int)
)
as s2
from
#a
) x
order by
s1,s2,c
With the output:
FW-1 4 1 -1
FW-1A 4 1 -1A
FW-2 4 2 -2
FW-3 4 3 -3
FW-10 4 10 -10
FW-11 4 11 -11
FW-12 4 12 -12
FW-13 4 13 -13
FW-A1 5 1 A1
FW-R1 5 1 R1
If the leading part is not fixed (FW-) you might need to add one additional sort field
Declare #a Table (c varchar(50))
Insert Into #a
Select 'FW-1'
Union Select 'FW-10'
Union Select 'FW-11'
Union Select 'FW-12'
Union Select 'FW-13'
Union Select 'FW-1A'
Union Select 'FW-2'
Union Select 'FW-3'
Union Select 'FW-R1'
Union Select 'FW-A1'
Union Select 'AB-A1'
Union Select 'AB-11'
;With CTE as
(Select 1 as ID
Union All
Select ID + 1 from CTE where ID < 100
)
Select * from
(
Select c
,SubString(c,1,PATINDEX('%[0-9]%',c)-1) as S0
,PATINDEX('%[0-9]%',c) as s1
,(Select Cast(
(Select Case
When SUBSTRING(c, ID, 1) LIKE '[0-9]'
Then SUBSTRING(c, ID, 1)
Else ''
End
From (Select * from CTE) AS X(ID)
Where ID <= LEN(c)
For XML PATH(''))
as int)
)
as s2
from
#a
) x
order by
s0,s1,s2,c

SQL 2005 Merge / concatenate multiple rows to one column

We have a bit of a SQL quandry. Say I have a results that look like this...
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | A
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | B
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | C
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | E
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | F
is there a way I can group these results within SQL to return as
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | A B C D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | E F
Any ideas people?
Many thanks
Dave
try this:
set nocount on;
declare #t table (id char(36), x char(1))
insert into #t (id, x)
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'A' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'B' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'C' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'D' union
select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'E' union
select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'F'
set nocount off
SELECT p1.id,
stuff(
(SELECT
' ' + x
FROM #t p2
WHERE p2.id=p1.id
ORDER BY id, x
FOR XML PATH('')
)
,1,1, ''
) AS YourValues
FROM #t p1
GROUP BY id
OUTPUT:
id YourValues
------------------------------------ --------------
61E77D90-D53D-4E2E-A09E-9D6F012EB59C A B C D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 E F
(2 row(s) affected)
EDIT
based on OP's comment about this needing to run for an existing query, try this:
;WITH YourBugQuery AS
(
--replace this with your own query
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' AS ColID , 'A' AS ColX
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'B'
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'C'
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'D'
union select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'E'
union select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'F'
)
SELECT p1.ColID,
stuff(
(SELECT
' ' + ColX
FROM YourBugQuery p2
WHERE p2.ColID=p1.ColID
ORDER BY ColID, ColX
FOR XML PATH('')
)
,1,1, ''
) AS YourValues
FROM YourBugQuery p1
GROUP BY ColID
this has the same results set as displayed above.
I prefer to define a custom user-defined aggregate. Here's an example of a UDA which will accomplish something very close to what you're asking.
Why use a user-defined aggregate instead of a nested SELECT? It's all about performance, and what you are willing to put up with. For a small amount of elements, you can most certainly get away with a nested SELECT, but for large "n", you'll notice that the query plan essentially runs the nested SELECT once for every row in the output list. This can be the kiss of death if you're talking about a large number of rows. With a UDA, it's possible to aggregate these values in a single pass.
The tradeoff, of course, is that the UDA requires you to use the CLR to deploy it, and that's something not a lot of people do often. In Oracle, this particular situation is a bit nicer as you can use PL/SQL directly to create your user-defined aggregate, but I digress...
Another way of doing it is to use the FOR XML PATH option
SELECT
[ID],
(
SELECT
[Value] + ' '
FROM
[YourTable] [YourTable2]
WHERE
[YourTable2].[ID] = [YourTable].[ID]
ORDER BY
[Value]
FOR XML PATH('')
) [Values]
FROM
[YourTable]
GROUP BY
[YourTable].[ID]