I had a table1 (id - unique)
|---|----------|
|id | array |
|---|----------|
|0 | [2, 4, 6]|
|1 | [3, 5, 1]|
|---|----------|
and table2
|---|----|
|id |val |
|---|----|
|1 | 23 |
|2 | 34 |
|3 | 19 |
|4 | 61 |
|5 | 47 |
|6 | 3 |
|---|----|
I don't now how to make a request like this:
SELECT val FROM table2 WHERE id = ANY(SELECT array FROM table1 WHERE id = 1)
Edit
Or simpler this does not work:
select 2 = any (select array[2, 4]);
ERROR: operator does not exist: integer = integer[]
LINE 1: select 2 = any (select array[2, 4]);
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
While this works:
select 2 = any ((select array[2, 4])::int[]);
?column?
----------
t
1)
SELECT val FROM table2
WHERE id = ANY((SELECT array FROM table1 WHERE id = 1)::int[])
2)
SELECT val FROM table2
WHERE ARRAY[id] <# (SELECT array FROM table1 WHERE id = 1)
3)
SELECT val FROM table2
WHERE id in (SELECT unnest(array) FROM table1 WHERE id = 1)
4)
SELECT val FROM table2
WHERE exists (SELECT 1 FROM table1 WHERE id = 1 and table2.id = ANY(array))
5) As you can see there are a lot of possibilities ;)
Related
is it possible to substitute the value generated by Dense_Rank() with a Newid() value in TSQL? I use Dense_Rank() for grouping but I need a uniqueidentifier generated instead of an integer. Thanks in advance.
There's no direct way to do this, but as I mentioned in my comment, you can get your dense_rank() for each record, then generate a NEWID() for each distinct Dense_Rank(), then join it back to itself.
CREATE TABLE test(f1 int, f2 char(1));
INSERT INTO test
VALUES (1, 'a'),
(1, 'b'),
(1, 'c'),
(2, 'a'),
(2, 'b'),
(3, 'a'),
(3, 'd'),
(3, 'g');
With dr AS (SELECT f1, f2, dense_rank() OVER (PARTITION BY f1 ORDER BY f2) as dr FROM test)
,dr_newid AS (SELECT dr, newid() as nid FROM (SELECT dr FROM dr GROUP BY dr) as drsub)
SELECT dr.f1, dr.f2, dr.dr, dr_newid.nid
FROM dr LEFT OUTER JOIN dr_newid ON dr.dr = dr_newid.dr
ORDER BY f1, f2;
+----+----+----+--------------------------------------+
| f1 | f2 | dr | nid |
+----+----+----+--------------------------------------+
| 1 | a | 1 | 966389AF-4C70-4AA8-A5C9-6F9537B8A1B8 |
| 1 | b | 2 | 73BE2978-B7D7-46B8-8B04-3103C8410575 |
| 1 | c | 3 | CB935CCA-AFE5-4D13-9583-0440DF1BEFE2 |
| 2 | a | 1 | 966389AF-4C70-4AA8-A5C9-6F9537B8A1B8 |
| 2 | b | 2 | 73BE2978-B7D7-46B8-8B04-3103C8410575 |
| 3 | a | 1 | 966389AF-4C70-4AA8-A5C9-6F9537B8A1B8 |
| 3 | d | 2 | 73BE2978-B7D7-46B8-8B04-3103C8410575 |
| 3 | g | 3 | CB935CCA-AFE5-4D13-9583-0440DF1BEFE2 |
+----+----+----+--------------------------------------+
One caveat here though... depending on how your box performs the join from dr to dr_newid it may generate unique newids for each distinct dense_rank value. Using a LEFT JOIN should trick the optimizer into generating the dr_newid intermediate result set once to be joined back. An INNER JOIN though may not.
If it's giving incorrect results, you may dump that dr_newid out to a temp table and then join back, forcing the server to derive the newid() once for each distinct dense_rank() and avoid tricks to force the optimizer's logic.
sqlfiddle here
I would like to select a number of tables and select the geometry (geom) and Name columns in each of the tables and append below each other. I have gotten as far as selecting the tables and their columns as shown below:
SELECT TABLE_NAME COLUMN_NAME
FROM INFORMATION_SCHEMA.columns
WHERE (TABLE_NAME LIKE '%HESA' OR
TABLE_NAME LIKE '%HEWH') AND
(COLUMN_NAME = 'geom' AND
COLUMN_NAME = 'Name');
How do you then take the tables:
id | geom | Name | id | geom | Name |
____________________ ____________________
1 | geom1 | Name1 | 1 | geom4 | Name4 |
2 | geom2 | Name2 | 2 | geom5 | Name5 |
3 | geom3 | Name3 | 3 | geom6 | Name6 |
And append the second table below the first, like this:
id | geom | Name |
____________________
1 | geom1 | Name1 |
2 | geom2 | Name2 |
3 | geom3 | Name3 |
1 | geom4 | Name4 |
2 | geom5 | Name5 |
3 | geom6 | Name6 |
Do I use UNION ALL or something else?
https://www.db-fiddle.com/f/75fgQMEWf9LvPj4xYMGWvA/0
based on your sample data:
do
'
declare
r record;
begin
for r in (
SELECT a.TABLE_NAME
FROM INFORMATION_SCHEMA.columns a
JOIN INFORMATION_SCHEMA.columns b on a.TABLE_NAME = b.TABLE_NAME and a.COLUMN_NAME = ''geom'' and b.COLUMN_NAME = ''name''
WHERE (a.TABLE_NAME LIKE ''oranges%'' OR a.TABLE_NAME LIKE ''%_db'')
) loop
execute format(''insert into rslt select geom, name from %I'',r.table_name);
end loop;
end;
'
;
Union All will do the job just fine:
SELECT
*
FROM (
(SELECT * FROM table_one)
UNION ALL
(SELECT * FROM table_two)
) AS tmp
ORDER BY name ASC;
I have added the external SELECT, to show you how you can order the whole result.
DB Fiddle can be found here
Table 1:
+-----+-----+
| TID | Rev |
+-----+-----+
| A | 20 |
| B | 100 |
| C | 10 |
+-----+-----+
Table 2:
+-----+-------+
| TID | Count |
+-----+-------+
| A | 2 |
| B | 3 |
| C | 2 |
+-----+-------+
Required:
Take 50% of rev from Table 1 and distribute using linear decay based on the count for a given TID in Table 2.
Example: For TID=A, table1: Rev=20 Table2: count=2
Step1: take 50% of Rev = 10
Step2: Distribute using decay(Divide by 2), so 10 and 5
+-----+-------+
| TID | Value |
+-----+-------+
| A | 10 |
| A | 5 |
| B | 50 |
| B | 25 |
| B | 12.5 |
| C | 5 |
| C | 2.5 |
+-----+-------+
The setup:
create table revs (tid text, rev numeric);
insert into revs values
('A', 20),
('B', 100),
('C', 10);
create table counts (tid text, ct int);
insert into counts values
('A', 2),
('B', 5),
('C', 2);
This is a case for recursive cte:
with recursive revrec(tid, rev, ct) as (
select tid, rev / 2, ct- 1
from revs
join counts using(tid)
union
select tid, rev / 2, ct- 1
from revrec
where ct > 0
)
select tid, rev
from revrec
order by tid, ct desc;
tid | rev
-----+---------------------
A | 10.0000000000000000
A | 5.0000000000000000
B | 50.0000000000000000
B | 25.0000000000000000
B | 12.5000000000000000
B | 6.2500000000000000
B | 3.1250000000000000
C | 5.0000000000000000
C | 2.5000000000000000
(9 rows)
I want to concatenate a field with previous and next rows. for example if I have this:
|ID|word|
|0 |Hi! |
|1 |How |
|2 |Are |
|3 |You |
I want to create a stored procedure with to input, 'before' and 'after' which indicate how many rows should use for previous and next of current row.
for example if we have before=1 and after=1 then we'll get this
|ID|word |
|0 |Hi! How |
|1 |Hi! How Are|
|2 |How Are You|
|3 |Are You |
and if we have before=2 and after=1 then we'll get this
|ID|word |
|0 |Hi! How |
|1 |Hi! How Are |
|2 |Hi! How Are You|
|3 |How Are You |
Thanks in advance
Check this:
DECLARE #before TINYINT = 2
DECLARE #after TINYINT = 1
SELECT ISNULL(( SELECT STUFF((SELECT ISNULL(TblBefore.word, '') + ' '
FROM Tbl TblBefore
WHERE TblBefore.Id BETWEEN T.Id - #before AND T.Id
- 1
FOR XML PATH('') ,
TYPE).value('.', 'varchar(max)'), 1, 0, '') AS ChildValues
), '') + T.Word + ' '
+ ISNULL(( SELECT STUFF((SELECT ISNULL(TblBefore.word, '') + ' '
FROM Tbl TblBefore
WHERE TblBefore.Id BETWEEN T.Id + 1 AND T.Id
+ #after
FOR XML PATH('') ,
TYPE).value('.', 'varchar(max)'), 1, 0,
'') AS ChildValues
), '')
FROM Tbl T
SELECT Columnname + ' ' + (
SELECT TOP 1 Myt2.Columnname
FROM table1 Myt2
WHERE Myt2.ColumnID < t1.ColumnID
ORDER BY
ColumnID
)
FROM table1 Myt1
ORDER BY
Myt1.ColumnID
This code snippet works for 2 levels...:) still not the complete answer. It may help to get you to nth level.
How I can sort a hierarchical table with CTE query ?
sample table :
|ID|Name |ParentID|
| 0| |-1 |
| 1|1 |0 |
| 2|2 |0 |
| 3|1-1 |1 |
| 4|1-2 |1 |
| 5|2-1 |2 |
| 6|2-2 |2 |
| 7|2-1-1 |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|1 |0 |1
| 3|1-1 |1 |2
| 4|1-2 |1 |2
| 2|2 |0 |1
| 5|2-1 |2 |2
| 7|2-1-1 |5 |3
| 6|2-2 |2 |2
another Sample :
an other sample :
|ID|Name |ParentID|
| 0| |-1 |
| 1|Book |0 |
| 2|App |0 |
| 3|C# |1 |
| 4|VB.NET |1 |
| 5|Office |2 |
| 6|PhotoShop |2 |
| 7|Word |5 |
and my favorite result is :
|ID|Name |ParentID|Level
| 0| |-1 |0
| 1|Book |0 |1
| 3|C# |1 |2
| 4|VB.NET |1 |2
| 2|App |0 |1
| 5|Office |2 |2
| 7|Word |5 |3
| 6|PhotoShop |2 |2
The hierarchyid datatype is able to represent hierarchical data, and already has the desired sorting order. If you can't replace your ParentID column, then you can convert to it on the fly:
(Most of this script is data setup, the actual answer is quite small)
declare #t table (ID int not null,Name varchar(10) not null,ParentID int not null)
insert into #t(ID,Name,ParentID)
select 0,'' ,-1 union all
select 1,'Book' ,0 union all
select 2,'App' ,0 union all
select 3,'C#' ,1 union all
select 4,'VB.NET' ,1 union all
select 5,'Office' ,2 union all
select 6,'PhotoShop' ,2 union all
select 7,'Word' ,5
;With Sensible as (
select ID,Name,NULLIF(ParentID,-1) as ParentID
from #t
), Paths as (
select ID,CONVERT(hierarchyid,'/' + CONVERT(varchar(10),ID) + '/') as Pth
from Sensible where ParentID is null
union all
select s.ID,CONVERT(hierarchyid,p.Pth.ToString() + CONVERT(varchar(10),s.ID) + '/')
from Sensible s inner join Paths p on s.ParentID = p.ID
)
select
*
from
Sensible s
inner join
Paths p
on
s.ID = p.ID
order by p.Pth
ORDER BY Name should work as desired:
WITH CTE
AS(
SELECT parent.*, 0 AS Level
FROM #table parent
WHERE parent.ID = 0
UNION ALL
SELECT parent.*, Level+1
FROM #table parent
INNER JOIN CTE prev ON parent.ParentID = prev.ID
)
SELECT * FROM CTE
ORDER BY Name
Here's your sample data(add it next time yourself):
declare #table table(ID int,Name varchar(10),ParentID int);
insert into #table values(0,'',-1);
insert into #table values(1,'1',0);
insert into #table values(2,'2',0);
insert into #table values(3,'1-1',1);
insert into #table values(4,'1-2',1);
insert into #table values(5,'2-1',2);
insert into #table values(6,'2-2',2);
insert into #table values(7,'2-1-1',5);
Result:
ID Name ParentID Level
0 -1 0
1 1 0 1
3 1-1 1 2
4 1-2 1 2
2 2 0 1
5 2-1 2 2
7 2-1-1 5 3
6 2-2 2 2