these are my table,
http://sqlfiddle.com/#!3/a8087/1
What i'm trying to achieve is insert into another new table by selecting from Tbl2 and CustTable.
E.g:
INSERT INTO tbl3
SELECT TOP(SELECT Counter FROM Tbl2) a.name, a.amount FROM custTable a
INNER JOIN Tbl2 b ON a.custId = b.custid
I want to insert X number of ROW base on CustId's [Counter].
It's not working because Subquery returned more than 1 value.
how can i fix the query in TOP()?
You can use Windowing functions to do rank the rows by customer, and then filter by the counter:
WITH cte as
(
SELECT a.Name, a.Amount, b.Counter,
ROW_NUMBER() OVER (PARTITION BY a.CustID ORDER BY a.Amount DESC) AS RN
FROM custTable a
INNER JOIN Tbl2 b ON a.custId = b.custid
)
SELECT cte.name, cte.amount
INTO tbl3
FROM cte
WHERE cte.rn <= Counter;
You'll need to choose an ORDER on each customer to determine 'which' of the TOP records get included (I've assumed you want the top amounts here)
I've also used SELECT ... INTO to create table 3 on the fly, but you can INSERT INTO if it is already created.
Updated your SqlFiddle here
Related
So I have :
CREATE TABLE A (id INT,type int,amount int);
INSERT INTO A (id,type,amount) VALUES (1,0,25);
INSERT INTO A (id,type,amount) VALUES (2,0,25);
INSERT INTO A (id,type,amount) VALUES (3,1,10);
CREATE TABLE B (id INT,A_ID int,txt text);
INSERT INTO B (id,A_id,txt) VALUES (1,1,'abc');
INSERT INTO B (id,A_id,txt) VALUES (2,1,'def');
INSERT INTO B (id,A_id,txt) VALUES (3,2,'xxx');
I run this query:
SELECT min(A.id), SUM(A.amount), COUNT(B.id) FROM A
LEFT JOIN B ON A.id = B.A_id
GROUP BY A.type
I get :
min(A.id) SUM(A.amount) COUNT(B.id)
1 75 3
3 10 0
But I'm instead expecting to get :
min(A.id) SUM(A.amount) COUNT(B.id)
1 50 3
3 10 0
Can someone help? What is the best way to achieve this exact result ?
I want group BY type and get SUM of grouped A.amount and get count() of all B corresponding to its foreign key.
here is the repro : https://www.db-fiddle.com/f/esu13uGLcgFDpX7aEQRMJR/0 please RUN sql code.
EDIT to add more detail : I know the result is correct if I remove group by we can see
1, 50, 2
2, 25, 1
But I expect the above result, what is the best way to achieve it ? I want make SUM of a TYPE then count all B related to this groupped A
Just a shorter version of the solution. It counts B_IDs first in the inner query, so I need to Sum the counts in the outer query.
SELECT min(A.id), SUM(A.amount), Sum(Bid) FROM A
LEFT JOIN (select count(id) as Bid, A_id from B group by A_id) as Bcount
ON A.id = Bcount.A_id
GROUP BY A.type
This can happen when you SUM from an 1-N relation.
The matching records can multiply the result.
For example, when 1 records in A are joined with 2 in B it returns 2 times the amount of A before the GROUP BY. So a SUM then doubles A.amount.
A way to get around that is using sub-queries that join one-on-one.
And a COUNT DISTINCT can be used to count unique id's.
So this just a way to get the SUM of A correct.
SELECT
q1.type,
q1.min_id,
q2.amount,
COALESCE(q1.totalB, 0) as totalB
FROM
(
SELECT
A.type,
MIN(A.id) AS min_id,
COUNT(DISTINCT B.id) AS totalB
FROM A
LEFT JOIN B ON B.A_id = A.id
GROUP BY A.type
) AS q1
JOIN
(
SELECT
type,
SUM(amount) AS amount
FROM A
GROUP BY type
) AS q2 ON q2.type = q1.type
View on DB Fiddle
The SQL is tested for MySql. But it's an ANSI standard SQL that would run on almost any RDBMS, including MS Sql Server.
one way of doing this would be to use ROW_NUMBER():
WITH CTE AS (SELECT A.id AS Aid,
A.[type],
A.amount,
B.id AS bid,
txt,
ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY B.id) AS RN
FROM A
LEFT JOIN B ON A.id = B.A_ID)
SELECT MIN(Aid) AS Min_A_ID,
SUM(CASE RN WHEN 1 THEN amount END) AS Amount,
COUNT(bid) AS BCount
FROM CTE
GROUP BY [type];
I also recommend getting rid of that text datatype and using varchar(MAX).
I need to execute a query something like below.
SELECT TO_CHAR(ROWNUM),
A.Name,
B.Order,
(SELECT * FROM (
SELECT ROUND(LAST_ORDER_AMOUNT,5) FROM ORDERS WHERE ID=A.id AND REQUEST_LEVEL='N' ORDER BY O_DATE DESC)
WHERE ROWNUM =1) AS AMOUNT
FROM Table1 A LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
But this gives me A.ID is invalid error in oracle. I need to get the first record from inner query as it will return multiple records.
Can someone please let me know how can i bind these tables to achieve my goal.
Thank you in advance.
You can rewrite subquery using WITH clause, not exactly sure on syntax but should be something like following.
WITH AmountQuery
AS (
SELECT ID
,ROUND(LAST_ORDER_AMOUNT, 5) AS AmountValue
,ROW_NUMBER() OVER ( ORDER BY O_DATE DESC ) AS RN
FROM ORDERS
WHERE REQUEST_LEVEL = 'N'
)
SELECT TO_CHAR(ROWNUM)
,A.Name
,B.Order
,C.AmountValue
FROM Table1 A
LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
LEFT JOIN AmountQuery C
ON a.ID = c.ID
AND c.RN = 1
here is SQLFiddle to show how it works.
http://sqlfiddle.com/#!4/696b6/36
Probably, LIMIT will do the job for you selecting just one record from the subquery (It worked for me in MySQL. I do not have Oracle, but I think it may be similar). Try something like this:
SELECT TO_CHAR(ROWNUM),
A.Name,
B.Order,
COALESCE( C.AMOUNT ) as AMOUNT,
FROM Table1 A LEFT JOIN Table2 B
ON A.TYPE_CODE = B.ENTITY_TYPE
LEFT JOIN ( SELECT ROUND(LAST_ORDER_AMOUNT,5) AS AMOUNT FROM ORDERS WHERE REQUEST_LEVEL='N' ORDER BY O_DATE DESC ) C ON C.ID = A.id
group by A.id;
I am trying to change my sub-query in to a join where it selects only one record in the sub-query. It seems to run the sub-query for each found record, taking over a minute to execute:
select afield1, afield2, (
select top 1 b.field1
from anothertable as b
where b.aForeignKey = a.id
order by field1
) as bfield1
from sometable as a
If I try to only select related records, it doesn't know how to bind a.id in the nested select.
select afield1, afield2, bfield1
from sometable a left join (
select top 1 id, bfield, aForeignKey
from anothertable
where anothertable.aForeignKey = a.id
order by bfield) b on
b.aForeignKey = a.id
-- Results in the multi-part identifier "a.id" could not be bound
If I hard code values in the nested where clause, the select duration drops from 60 seconds to under five. Anyone have any suggestions on how to join the two tables while not processing every record in the inner table?
EDIT:
I ended up adding
left outer join (
select *, row_number() over (partition by / order by) as rank) b on
b.aforeignkey = a.id and b.rank = 1
went from ~50 seconds to 8 for 22M rows.
Try this:
WITH qry AS
(
SELECT afield1,
afield2,
b.field1 AS bfield1,
ROW_NUMBER() OVER(PARTITION BY a.id ORDER BY field1) rn
FROM sometable a LEFT JOIN anothertable b
ON b.aForeignKey = a.id
)
SELECT *
FROM qry
WHERE rn = 1
Try this
select afield1,
afield2,
bfield1
from sometable a
left join
(select top 1 id, bfield, aForeignKey from anothertable where aForeignKey in(a.id) order by bfield) b on b.aForeignKey = a.id
Hallo,
I have a join table, said tableA and tableB. tableA have a column called Amount. tableB have a column called refID. I would like to total up the Amount column when refID having the same value. I was using SUM in my query, but it throw me an error:
ORA-30483: window functions are not allowed here
30483. 00000 - "window functions are not allowed here"
*Cause: Window functions are allowed only in the SELECT list of a query.
And, window function cannot be an argument to another window or group
function.
Here is my query for your reference:
select *
from (
select SUM(A.Amount), B.refId, Rank() over (partition by B.refID order by B.id desc) as ranking
from table A
left outer join table B on A.refID = B.refID
)
where ranking=1;
May I know is there any alternate solution in order for me to SUM the Amount?
THanks #!
select
SUM(A.Amount),
B.refId
from table A
left outer join table B on A.refID = B.refID
GROUP BY
B.refId
SELECT *
FROM (
SELECT A.Amount, B.refId,
Rank() over (partition by A.refID order by B.id desc) as ranking,
SUM(amount) OVER (PARTITION BY a.refId) AS asum
FROM tableA A
LEFT JOIN
tableB B
ON B.refID = A.refID
)
WHERE ranking = 1
Declare #T table(id int)
insert into #T values (1),(2)
Declare #T1 table(Tid int,fkid int,Amount int)
insert into #T1 values (1,1,200),(2,1,250),(3,2,100),(4,2,25)
Select SUM(t1.Amount) as amount,t1.fkid as id from #T t
left outer join #T1 t1 on t1.fkid = t.id group by t1.fkid
SELECT refid, sum(a.amount)
FROM table AS a LEFT table AS b USING (refid)
GROUP BY refid;
I'm a little confused. The query you posted did not have a SUM function anywhere, and performed a self-join of a table named "TABLE" to itself. I'm going to guess that you actually have two tables (I'll call them TABLE_A and TABLE_B), in which case the following should do it:
SELECT a.REFID, SUM(a.AMOUNT)
FROM TABLE_A a
INNER JOIN TABLE_B b
ON (b.REFID = a.REFID)
GROUP BY a.REFID;
If I understood your question you only wanted results when you have a TABLE_B.REFID which matches a TABLE_A.REFID, so an INNER JOIN would be appropriate.
Share and enjoy.
Table1 has columns (id, a, b, c, group). There are several rows that have the same group, but id is always unique. I would like to SELECT group,a,b FROM Table1 WHERE the group is distinct. However, I would like the returned data to be from the row with the greatest id for that group.
Thus, if we have the rows
(id=10, a=6, b=40, c=3, group=14)
(id=5, a=21, b=45, c=31, group=230)
(id=4, a=42, b=65, c=2, group=230)
I would like to return these 2 rows:
[group=14, a=6,b=40] and
[group=230, a=21,b=45] (because id=5 > id=4)
Is there a simple SELECT statement to do this?
Try:
select grp, a, b
from table1 where id in
(select max(id) from table1 group by grp)
You can do it using a self join or an inner-select. Here's inner select:
select `group`, a, b from Table1 AS T1
where id=(select max(id) from Table1 AS T2 where T1.`group` = T2.`group`)
And self-join method:
select T1.`group`, T2.a, T2.b from
(select max(id) as id,`group` from Table1 group by `group`) T1
join Table1 as T2 on T1.id=T2.id
2 selects, your inner select gets:
SELECT MAX(id) FROM YourTable GROUP BY [GROUP]
Your outer select joins to this table.
Think about it logically, the inner select gets a sub set of the data you need.
The outer select inner joins to this subset and can get further data.
SELECT [group], a, b FROM YourTable INNER JOIN
(SELECT MAX(id) FROM YourTable GROUP BY [GROUP]) t
ON t.id = YourTable.id
SELECT mi.*
FROM (
SELECT DISTINCT grouper
FROM mytable
) md
JOIN mytable mi
ON mi.id =
(
SELECT id
FROM mytable mo
WHERE mo.grouper = md.grouper
ORDER BY
id DESC
LIMIT 1
)
If your table is MyISAM or id is not a PRIMARY KEY, then make sure you have a composite index on (grouper, id).
If your table is InnoDB and id is a PRIMARY KEY, then a simple index on grouper will suffice (id, being a PRIMARY KEY, will be implictly included).
This will use an INDEX FOR GROUP-BY to build the list of distinct groupers, and for each grouper it will use the index access to find the maximal id.
Don't know how to do it in mysql. But the following code will work for MsSQL...
SELECT Y.* FROM
(
SELECT DISTINCT [group], MAX(id) ID
FROM Table1
GROUP BY [group]
) X
INNER JOIN Table1 Y ON X.ID=Table1.ID