I have a problem with some query from given result set i need to select the less detail row from table under some conditions.
I have three selects that after union return this table
SELECT A_ID, B_ID, 1 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 1
UNION
SELECT A_ID, B_ID, 2 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 2
UNION
SELECT A_ID, B_ID, 3 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 3
The result can be something like this
1000 100 1
1000 200 2
1000 300 3
From this table the final result should be 1000 100 1
The best case scenario is when a value is found then is no longer searched in next select.
Some ideas ?
EDIT:
The solution presented by 'Jeffrey Kemp' one query works fine.
1000 100 1
1000 200 2
1000 300 3
1001 200 2
1001 300 3
result
1000 100 1
1001 200 2
Database: Oracle Database 10g Release 10.2.0.4.0 - 64bit Production
Without knowing the details of your query, this is one option to consider:
SELECT * FROM (
SELECT * FROM (
SELECT A_ID, B_ID, 1 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 1
UNION
SELECT A_ID, B_ID, 2 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 2
UNION
SELECT A_ID, B_ID, 3 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 3
)
ORDER BY 3
) WHERE ROWNUM = 1;
An alternative is to add conditions to the queries to determine if they need to run at all:
SELECT A_ID, B_ID, 1 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 1
UNION
SELECT A_ID, B_ID, 2 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 2
WHERE NOT EXISTS (SPECIFIC CONDITION FOR LEVEL 1)
UNION
SELECT A_ID, B_ID, 3 FROM MY_TABLE JOIN MY_TABLE2 ON SPECIFIC CONDITION FOR LEVEL 3
WHERE NOT EXISTS (SPECIFIC CONDITION FOR LEVEL 1)
AND NOT EXISTS (SPECIFIC CONDITION FOR LEVEL 2)
Of course, I don't know the nature of your "specific conditions" so I don't know if this will work for you or not.
Related
In my postgres table, I have two columns of interest: id and name - my goal is to only keep records where id has more than one value in name. In other words, would like to keep all records of ids that have multiple values and where at least one of those values is B
UPDATE: I have tried adding WHERE EXISTS to the queries below but this does not work
The sample data would look like this:
> test
id name
1 1 A
2 2 A
3 3 A
4 4 A
5 5 A
6 6 A
7 7 A
8 2 B
9 1 B
10 2 B
and the output would look like this:
> output
id name
1 1 A
2 2 A
8 2 B
9 1 B
10 2 B
How would one write a query to select only these kinds records?
Based on your description you would seem to want:
select id, name
from (select t.*, min(name) over (partition by id) as min_name,
max(name) over (partition by id) as max_name
from t
) t
where min_name < max_name;
This can be done using EXISTS:
select id, name
from test t1
where exists (select *
from test t2
where t1.id = t2.id
and t1.name <> t2.name) -- this will select those with multiple names for the id
and exists (select *
from test t3
where t1.id = t3.id
and t3.name = 'B') -- this will select those with at least one b for that id
Those records where for their id more than one name shines up, right?
This could be formulated in "SQL" as follows:
select * from table t1
where id in (
select id
from table t2
group by id
having count(name) > 1)
I am stuck at this T-SQL query.
I have table below
Age SectioName Cost
---------------------
1 Section1 100
2 Section1 200
1 Section2 500
3 Section2 100
4 Section2 200
Lets say for each section I can have maximum 5 Age. In above table there are some missing Ages. How do I insert missing Ages for each section. (Possibly without using cursor). The cost would be zero for missing Ages
So after the insertion the table should look like
Age SectioName Cost
---------------------
1 Section1 100
2 Section1 200
3 Section1 0
4 Section1 0
5 Section1 0
1 Section2 500
2 Section2 0
3 Section2 100
4 Section2 200
5 Section2 0
EDIT1
I should have been more clear with my question. The maximum age is dynamic value. It could be 5,6,10 or someother value but it will be always less than 25.
I think I got it
;WITH tally AS
(
SELECT 1 AS r
UNION ALL
SELECT r + 1 AS r
FROM tally
WHERE r < 5 -- this value could be dynamic now
)
select n.r, t.SectionName, 0 as Cost
from (select distinct SectionName from TempFormsSectionValues) t
cross join
(select ta.r FROM tally ta) n
where not exists
(select * from TempFormsSectionValues where YearsAgo = n.r and SectionName = t.SectionName)
order by t.SectionName, n.r
You can use this query to select missing value:
select n.num, t.SectioName, 0 as Cost
from (select distinct SectioName from table1) t
cross join
(select 1 as num union select 2 union select 3 union select 4 union select 5) n
where not exists
(select * from table1 where table1.age = n.num and table1.SectioName = t.SectioName)
It creates a Cartesian product of sections and numbers 1 to 5 and then selects those that doesn't exist yet. You can then use this query for the source of insert into your table.
SQL Fiddle (it has order by added to check the results easier but it's not necessary for inserting).
Use below query to generate missing rows
SELECT t1.Age,t1.Section,ISNULL(t2.Cost,0) as Cost
FROM
(
SELECT 1 as Age,'Section1' as Section,0 as Cost
UNION
SELECT 2,'Section1',0
UNION
SELECT 3,'Section1',0
UNION
SELECT 4,'Section1',0
UNION
SELECT 5,'Section1',0
UNION
SELECT 1,'Section2',0
UNION
SELECT 2,'Section2',0
UNION
SELECT 3,'Section2',0
UNION
SELECT 4,'Section2',0
UNION
SELECT 5,'Section2',0
) as t1
LEFT JOIN test t2
ON t1.Age=t2.Age AND t1.Section=t2.Section
ORDER BY Section,Age
SQL Fiddle
You can utilize above result set for inserting missing rows by using EXCEPT operator to exclude already existing rows in table -
INSERT INTO test
SELECT t1.Age,t1.Section,ISNULL(t2.Cost,0) as Cost
FROM
(
SELECT 1 as Age,'Section1' as Section,0 as Cost
UNION
SELECT 2,'Section1',0
UNION
SELECT 3,'Section1',0
UNION
SELECT 4,'Section1',0
UNION
SELECT 5,'Section1',0
UNION
SELECT 1,'Section2',0
UNION
SELECT 2,'Section2',0
UNION
SELECT 3,'Section2',0
UNION
SELECT 4,'Section2',0
UNION
SELECT 5,'Section2',0
) as t1
LEFT JOIN test t2
ON t1.Age=t2.Age AND t1.Section=t2.Section
EXCEPT
SELECT Age,Section,Cost
FROM test
SELECT * FROM test
ORDER BY Section,Age
http://www.sqlfiddle.com/#!3/d9035/11
I have a query
SELECT id_anything FROM table1 JOIN table2 USING (id_tables)
Now, i have a situation which is:
If that join returns two rows from table2 i want to show the id_anything from table1 (1 row only)
and if the join from table2 returns 1 row, i want to show id_anything from table2.
Ps: id_anything from table 2 returns different values
Example data:
table1
id_tables | id_anything
1 | 1
table2
id_tables | id_anything
1 | 10
1 | 100
Return expected: 1
First, get the value you may want to return and the basis for deciding which to return together into one row.
SELECT table1.id_tables, table1.id_anything AS table1_id, MIN(table2.id_anything) AS table2_id, COUNT(*)
FROM table1 JOIN table2 USING (id_tables)
GROUP BY table1.id_tables, table1.id_anything
The aggregate function you use doesn't really matter since you'll only be using the value if there is only one.
You can then pick the relevant value:
WITH join_summary AS (
SELECT table1.id_tables, table1.id_anything AS table1_id, MIN(table2.id_anything) AS table2_id, COUNT(*) AS match_count
FROM table1 JOIN table2 USING (id_tables)
GROUP BY table1.id_tables, table1.id_anything
)
SELECT id_tables, CASE WHEN (match_count > 1) THEN table1_id ELSE table2_id END AS id_anything
FROM join_summary
I am teaching myself T-SQL and am struggling to comprehend the following example..
Suppose you want to display several nonaggregated columns along with
some aggregate expressions that apply to the entire result set or to a
larger grouping level. For example, you may need to display several
columns from the Sales.SalesOrderHeader table and calculate the
percent of the TotalDue for each sale compared to the TotalDue for all
the customer’s sales. If you group by CustomerID, you can’t include
other nonaggregated columns from Sales.SalesOrderHeader unless you
group by those columns. To get around this, you can use a derived
table or a CTE.
Here are two examples given...
SELECT c.CustomerID, SalesOrderID, TotalDue, AvgOfTotalDue,
TotalDue/SumOfTotalDue * 100 AS SalePercent
FROM Sales.SalesOrderHeader AS soh
INNER JOIN
(SELECT CustomerID, SUM(TotalDue) AS SumOfTotalDue,
AVG(TotalDue) AS AvgOfTotalDue
FROM Sales.SalesOrderHeader
GROUP BY CustomerID) AS c ON soh.CustomerID = c.CustomerID
ORDER BY c.CustomerID;
WITH c AS
(SELECT CustomerID, SUM(TotalDue) AS SumOfTotalDue,
AVG(TotalDue) AS AvgOfTotalDue
FROM Sales.SalesOrderHeader
GROUP BY CustomerID)
SELECT c.CustomerID, SalesOrderID, TotalDue,AvgOfTotalDue,
TotalDue/SumOfTotalDue * 100 AS SalePercent
FROM Sales.SalesOrderHeader AS soh
INNER JOIN c ON soh.CustomerID = c.CustomerID
ORDER BY c.CustomerID;
Why doesn't this query produce the same result..
SELECT CustomerID, SalesOrderID, TotalDue, AVG(TotalDue) AS AvgOfTotalDue,
TotalDue/SUM(TotalDue) * 100 AS SalePercent
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, SalesOrderID, TotalDue
ORDER BY CustomerID
I'm looking for someone to explain the above examples in another way or step through it logically so I can understand how they work?
The aggregates in this statement (i.e. SUM and AVG) don't do anything:
SELECT CustomerID, SalesOrderID, TotalDue, AVG(TotalDue) AS AvgOfTotalDue,
TotalDue/SUM(TotalDue) * 100 AS SalePercent
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, SalesOrderID, TotalDue
ORDER BY CustomerID
The reason for this is you're grouping by TotalDue, so all records in the same group have the same value for this field. In the case of AVG this means you're guarenteed for AvgOfTotalDue to always equal TotalDue. For SUM it's possible you'd get a different result, but as you're also grouping by SalesOrderID (which I'd imagine is unique in the SalesOrderHeader table) you will only have one record per group, so again this will always equal the TotalDue value.
With the CTE example you're only grouping by CustomerId; as a customer may have many sales orders associated with it, these aggregate values will be different to the TotalDue.
EDIT
Explanation of the aggregate of field included in group by:
When you group by a value, all rows with that same value are collected together and aggregate functions are performed over them. Say you had 5 rows with a total due of 1 and 3 with a total due of 2 you'd get two result lines; one with the 1s and one with the 2s. Now if you perform a sum on these you have 3*1 and 2*2. Now divide by the number of rows in that result line (to get the average) and you have 3*1/3 and 2*2/2; so things cancel out leaving you with 1 and 2.
select totalDue, avg(totalDue)
from (
select 1 totalDue
union all select 1 totalDue
union all select 1 totalDue
union all select 2 totalDue
union all select 2 totalDue
) x
group by totalDue
select uniqueId, totalDue, avg(totalDue), sum(totalDue)
from (
select 1 uniqueId, 1 totalDue
union all select 2 uniqueId, 1 totalDue
union all select 3 uniqueId, 1 totalDue
union all select 4 uniqueId, 2 totalDue
union all select 5 uniqueId, 2 totalDue
) x
group by uniqueId
Runnable Example: http://sqlfiddle.com/#!2/d41d8/21263
Let's sat I have a Table 'A' with rows:
A
B
C
D
Is there a simple way to do a cross join that creates
A 1
A 2
A 3
A 4
...
D 1
D 2
D 3
D 4
without creating a second table?
Something like:
SELECT *
FROM A
CROSS JOIN (1,2,3,4)
something like that should work, i guess
select * from A cross join (select 1 union all select 2 union all select 3 union all select 4) as tmp
you will create a second table, but you won't persist it.
The following would work for a table of any size (though I only tested it against 6 rows). It uses the ranking functions available in SQL Server 2005 and up, but the idea should be adaptible to any RDBMS.
SELECT ta.SomeColumn, cj.Ranking
from TableA ta
cross join (select row_number() over (order by SomeColumn) Ranking from TableA) cj
order by ta.SomeColumn, cj.Ranking
You should be able to achieve this via
select * from A cross join
(select 1
union all
select 2
union all
select 3
union all
select 4)