I am trying to order by columns from another table, heres an example of the error i am getting
DECLARE #UserID1 varchar(31), #UserID2 varchar(31), #UserID3 varchar(31), #UserID4 varchar(31)
--getting data from table
SELECT #UserID1 = ID1, #UserID2 = ID2, #UserID3 = ID3, #UserID4 = ID4
FROM USER_INFO
WHERE idref = #id
--select some data from another table with the values we got from USER_INFO table
SELECT age, name, location
FROM USER_DATA
WHERE NameId in(#UserID1, #UserID2, #UserID3, #UserID4)
ORDER BY #UserID1, #UserID2, #UserID3, #UserID4 -- this errors
The returned error is
The SELECT item identified by the ORDER BY number 1 contains a
variable as part of the expression identifying a column position.
Variables are only allowed when ordering by an expression referencing
a column name.
I am trying to order by ID1, ID2, ID3, ID4 FROM USER_INFO in ascending order
You can do it in this way:
SELECT age, name, location
FROM USER_DATA
WHERE NameId in(#UserID1, #UserID2, #UserID3, #UserID4)
ORDER BY CASE NameId
WHEN #UserID1 THEN 1
WHEN #UserID2 THEN 2
WHEN #UserID3 THEN 3
WHEN #UserID4 THEN 4
END
This will put records with NameId matching #UserID1 first, then records with NameId matching #UserID2, then #UserID3, and so on.
SELECT age, name, location
FROM USER_DATA UD
INNER JOIN USER_INFO UI
ON (UD.NameId=UI.ID1 OR UD.NameId=UI.ID2 OR UD.NameId=UI.ID3 OR UD.NameId=UI.ID4)
WHERE UI.idref = #id
AND NameId in(ID1, ID2, ID3, ID4)
ORDER BY ID1, ID2, ID3, ID4
OR
SELECT age, name, location
FROM USER_DATA UD
, USER_INFO UI
WHERE UI.idref = #id
AND NameId in(ID1, ID2, ID3, ID4)
ORDER BY ID1, ID2, ID3, ID4
Related
I have a simple table:
Main_ID
Sub_ID1
Sub_ID2
ID1
ID2
ID3
ID2
ID4
ID5
ID3
ID7
ID12
Where a product in Main_ID is made with products in Sub_ID1 and Sub_ID2.
I would like, for a given id, have all the products (sub_ids) necessary for its realisation.
For example: For the id ID1, I will have ID2, ID3, ID4, ID5, ID7, ID12.
(ID1 is made with ID2 and ID3, but ID2 is made with ID4 and ID5, and ID3 is made with ID7 and ID12, etc.)
I've tried some left join, but I miss something I guess.
SELECT t1.Main_ID
FROM my_table t1
INNER JOIN my_table t2 ON t2.Sub_ID1 t1.Main_ID OR t2.Sub_ID2 t1.Main_ID
WHERE t1.Main_ID LIKE 'ID1'
You can do this in a reliable way using a recursive query.
Although you need to do a preprocessing step first: "Sub_ID1" and "Sub_ID2" should be found within one single Sub_ID column, using the UNION ALL operator. We're calling the output of this step as "crafted table".
Then you can apply recursion defining these two steps:
base step, select the "main_id" record you want to inspect
recursive step, joining base-step table with the crafted table on matching <"Main_ID", "SubID">
WITH RECURSIVE one_subid AS (
SELECT Main_ID, Sub_ID1 AS Sub_ID FROM tab
UNION ALL
SELECT Main_ID, Sub_ID2 AS Sub_ID FROM tab
), cte_rec AS (
SELECT Main_ID, Sub_ID FROM one_subid WHERE Main_ID = 'ID1'
UNION ALL
SELECT t2.Sub_ID, t1.Sub_ID
FROM one_subid t1
INNER JOIN cte_rec t2 ON t1.Main_ID = t2.Sub_ID
)
SELECT Sub_ID FROM cte_rec
Output for 'Main_ID = ID1':
sub_id
ID2
ID3
ID4
ID7
ID5
ID12
Check the demo here.
I have two tables.
TABLE A:
OBJECTID ID
NULL 41230
NULL 00004
NULL 00005
TABLE B:
OBJECTID ID
241231 00001
241230 00002
I'm trying to write a query that increments values for the OBJECTID field in Table A based on the max value in Table B. For example the OBJECTID field for the first row in Table A would then be 241232.
Using ROW_NUMBER() over (Order by OBJECTID ASC) works if I wanted to start with the value 1 and increment. But I need it to join on Table B and start on Table B's max value and then increment.
I've tried this but get a query error Query error: Table-valued function not found tableB:
UPDATE `tableA`
SET OBJECTID = (SELECT MAX(OBJECTID) as seq
FROM `tableB`
((SELECT ROW_NUMBER() over (Order by seq ASC))
)) WHERE OBJECTID IS NULL;
In BigQuery is easier create a new table that overwrite the actual. You can do it with this select:
with max_id as (
select max(objectid) as objectid from tableB
),
table_a_new_id as (
select
* except (objectid),
(select objectid from max_id) + dense_rank() over (order by id) as objectid
from tableA
where objectid is null
)
select * from table_a_new_id
union all
select * from tableA where objectid is not null
If you can't replace the table directly, you can save the result in a temporary table and then run the update:
update tableA
set tableA.objectid = new_table_a.objectid
from temp_new_tableA
where tableA.objectid is null and tableA.id = temp_new_tableA.id
Tables: I have 3 tables
They are cust, new_cust, old_cust
all of them have 3 columns, they are id, username, name
each of them have possibilities to have same data as the others.
I would like to make "whole" table that consisting all of them but only the uniques.
I've Tried
Creating a dummy table
I've tried to create the dummy table called "Temp" table by
select *
into Temp
from cust
insert all table to dummy
Then I insert all of them into they Temp table
insert into temp
select * from new_cust
insert into temp
select * from old_cust
taking uniques using distinct
After they all merged I'm using distinct to only take the unique id value
select distinct(id), username, fullname
into Whole
from temp
it did decreasing some rows
Result
But after I move it to whole table I would like to put primary key on id but I got the message that there are some duplicate values. Is there any other way?
I am guessing that you want unique ids. And you want these prioritized by the tables in some order. If so, you can do this with union all and row_number():
select id, username, name
from (select c.*,
row_number() over (partition by id order by priority) as seqnum
from ((select id, username, name, 1 as priority
from new_cust
) union all
(select id, username, name, 2 as priority
from cust
) union all
(select id, username, name, 3 as priority
from old_cust
)
) c
) c
where seqnum = 1;
Try this:
insert into temp
select * from new_cust
UNION
select * from old_cust
Union will avoid the duplicate entries and you can then create a primary key on ID column
Try this below query...
WITH cte as (
SELECT id, username, NAME,
ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY t1.username, t1.name ) AS rn
FROM cust t1
LEFT JOIN new_cust t2 ON t1.Id = t2.Id
LEFT JOIN old_cust t3 ON t2.Id = t3.Id
)
SELECT id, username, NAME
FROM cte
WHERE rn = 1
Note:-
Put all the query inside a CTE(Common table expression)
with a new column(rn) that you will use to filter the results.
This new Column will produce ROW_NUMBER()....PARTITION BY username,name.....
But after I move it to whole table I would like to put primary key on
id but I got the message that there are some duplicate values.?
That's because You are trying to insert ID value from each of the tables to Whole table.
Just insert username and name and skip ID. ID is IDENTITY and it MUST be unique.
Run this on Your current Whole table to see if You have duplicated Id's:
select COUNT(ID), username
from whole
GROUP BY username
HAVING COUNT(ID) > 1
To get unique customers recreate table Whole and make ID col IDENTITY:
IF OBJECT_ID ('dbo.Whole') IS NOT NULL DROP TABLE dbo.Whole;
CREATE TABLE Whole (ID INT NOT NULL IDENTITY(1,1), Name varchar(max), Username varchar(max))
Insert values into Whole table:
INSERT INTO Whole
SELECT Name, Username FROM cust
UNION
SELECT Name, Username FROM new_cust
UNION
SELECT Name, Username FROM old_cust
Make ID col PK.
What does Unique mean for your row ?
If it is only the username, and you don't care about keeping the old ID values,
this will favor the new_cust data over the old_cust data.
SELECT
ID = ROW_NUMBER() OVER (ORDER BY all_temp.username)
, all_temp.*
INTO dbo.Temp
FROM
(
SELECT nc.username, nc.[name] FROM new_cust AS nc
UNION
SELECT oc.username, oc.[name]
FROM old_cust AS oc
WHERE oc.username NOT IN (SELECT nc1.username FROM new_cust AS nc1) --remove the where part if needed
) AS all_temp
ALTER TABLE dbo.Temp ALTER COLUMN ID INTEGER NOT NULL
ALTER TABLE dbo.Temp ADD PRIMARY KEY (ID)
If by Unique you mean both the username and name then just remove the where part in the union
I have a table which has three columns with three records. How can I select first value of the first column, second value of the second column, third value of the third column?
table
============
test_tab
id1 id2 id2
=== === ====
100 400 700
200 500 800
300 600 900
Required output like :
100 500 900
How can I achieve this by using Oracle SQL or PL/SQL?
First of all, How you would identify which row is the first and which one is second?
Oracle does not guarantee the order of the records, it must be ordered using order by clause explicitly else it will be, we can say random order (The default query output)
With your test data and result, You can use the following query:
Note: I am considering the third column as ID3 and ordering the rows using ID1
SELECT
MAX(CASE RN
WHEN 1 THEN ID1
END) AS ID1,
MAX(CASE RN
WHEN 2 THEN ID2
END) AS ID2,
MAX(CASE RN
WHEN 3 THEN ID3
END) AS ID3
FROM
(
SELECT
ID1,
ID2,
ID3,
ROW_NUMBER() OVER(
ORDER BY
ID1
) RN
FROM
TEST_TAB
);
Cheers!!
You will need a means of establishing what "first" means.
In Oracle, here is one way to address the example from your question:
create table test_tab(
id1 integer,
id2 integer,
id3 integer
);
insert into test_tab values(100,400,700);
insert into test_tab values(200,500,800);
insert into test_tab values(300,600,900);
commit;
select sum(decode(pos, 1, id1, null)) id1,
sum(decode(pos, 2, id2, null)) id2,
sum(decode(pos, 3, id3, null)) id3
from(
-- this subquery produces a rank column for the whole dataset
-- with an explicit order
select id1, id2, id3, rank() over (order by id1, id2, id3) pos from TEST_TAB
);
In this implementation, the subquery is used to establish an ordering of the rows, adding a new pos column based on the rank() function.
The sum(decode(pos, 3, id3, null)) construct is an Oracle idiom for picking one specific row (row 3 in this case) while ignoring the others.
Basically, for your three rows, the decode will result in NULL for any row but the one with the specified number, so the expression for id3 will only have a non-null value for the third row, hence the sum over the group will be equal to id3 in row 3.
There are many ways to do it, this is just one, and you will likely need to make some adjustments to this implementation for it to work properly in your real code.
let's say result of my select statements as follows (I have 5 of those):
Id Animal AnimalId
1 Dog Dog1
1 Cat Cat57
Id Transport TransportId
2 Car Car100
2 Plane Plane500
I'd like to get a result as follows:
Id Animal AnimalId Transport TransportId
1 Dog Dog1
1 Cat Cat57
2 Car Car100
2 Plane Plane500
What I can do is I can crate a tablevariable and specify all possible columns and insert records from each select statement into it. But maybe better solution like PIVOT?
Edit
queries: 1st: Select CategoryId as Id, Animal, AnimalId from Animal
2nd: Select CategoryId as Id, Transport, TransportId from Transport
How about this, if you need them in the same rows, this gets the row_number() for each row and joins on those:
select a.id,
a.aname,
a.aid,
t.tname,
t.tid
from
(
select id, aname, aid, row_number() over(order by aid) rn
from animal
) a
left join
(
select id, tname, tid, row_number() over(order by tid) rn
from transport
) t
on a.rn = t.rn
see SQL Fiddle with Demo
If you don't need them in the same row, then use UNION ALL:
select id, aname, aid, 'Animal' tbl
from animal
union all
select id, tname, tid, 'Transport'
from transport
see SQL Fiddle with Demo
Edit #1, here is a version with an UNPIVOT and PIVOT:
select an_id, [aname], [aid], [tname], [tid]
from
(
select *, row_number() over(partition by col order by col) rn
from animal
unpivot
(
value
for col in (aname, aid)
) u
union all
select *, row_number() over(partition by col order by col) rn
from transport
unpivot
(
value
for col in (tname, tid)
) u
) x1
pivot
(
min(value)
for col in([aname], [aid], [tname], [tid])
) p
order by an_id
see SQL Fiddle with Demo
This would do it for you:
SELECT
ID, field1, field2, '' as field3, '' as field4
FROM sometable
UNION ALL
SELECT
ID, '', '', field3, field4
FROM someothertable
create table Animal (
Animal varchar(50)
,AnimalID varchar(50)
)
create table Transport (
Transport varchar(50)
,TransportID varchar(50)
)
insert into Animal values ('Dog', 'Dog1')
insert into Animal values ('Cat', 'Cat57')
insert into Transport values ('Car', 'Car100')
insert into Transport values ('Plane', 'Plane500')
select ID = 1
,A.Animal
,A.AnimalID
,Transport = ''
,TransportID = ''
from Animal A
union
select ID = 2
,Animal = ''
,AnimalID = ''
,T.Transport
,T.TransportID
from Transport T
To get it in the format you want, select the values you want, and then null (or an empty string) for the other columns.
SELECT
CategoryId as Id,
Animal as 'Animal',
AnimalId as 'AnimalId',
null as 'Transport',
null as 'TransportId'
FROM Animal
UNION
SELECT
CategoryId as Id,
null as 'Animal',
null as 'AnimalId',
Transport as 'Transport',
TransportId as 'TransportId'
FROM Transport
I'm still not sure of the purpose of this, but this should give the output you want.
You shouldn't need to pivot, your results are already fine.
If you want, you can just UNION all 5 statements together in the same format as the first select: ID/Category/CategoryID. Then you'll get one long result set with all 5 sets appended 3 columns wide.
Is that what you want? Or do you need to distinguish between 'categories'?
given your example, try:
Select CategoryId as Id, Animal, AnimalId from Animal
union all
Select CategoryId as Id, Transport, TransportId from Transport
if you want, you can alias the columns like:
Select CategoryId as Id, Animal as category, AnimalId as categoryID from Animal
union all
Select CategoryId as Id, Transport, TransportId from Transport
you really don't need to pivot, just space out your columns like you were thinking initially. You don't pivot to move columns, you pivot to perform an aggregate function over grouped data.