The issue arises from the need to return values from need to return a single-row result set that will be used for a web service.
For example, if I have a select statement which currently returns a result set with 3 columns and 1 row, is there a way to "append" a value to it in its own column? The new value could be the result of any arbitrary select which returns exactly one row.
select a, b, c from d where a = 'id' gives
col1 col2 col3
a b c
The new select should give:
col1 col2 col3 col4
a b c *NEW*
Arbitrary in this case is used to mean not necessarily related to any of the values or tables in the original select statement.
I want to know how to do this in Oracle, but hopefully there is a solution which uses standard SQL features so most databases will handle it.
EDIT: By NEW I don't mean the string literal 'NEW', but I mean the result of the new select statement that I want to "append".
If you want a new select statement, you can do that in two ways. One is a select within a select:
select col1, col2, col3,
(select 'NEW' from d limit 1) as col4
from d
The other is a cross join:
select d.col1, d.col2, d.col3, const.col4
from d cross join
(select 'NEW' as col4 from d limit 1) const
I am using a simple subquery just as an example. I assume your subquery is a bit more complicated.
this type of structure will work. note you will get a cross join when there are more than one row.
select a,b,c,d
from ( select a,b,c from dual )
, (select d from dual )
select
a, b, c,
(select smth from table2 limit 1) as col4 as col4
from d where a = 'id'
The second query should return exactly one row and one column
Related
I have a table with 2 columns, each column is a FK to the same entity
Col1 and col2 are unique
I'm looking to create a query that recursively attempt a self join from Col2 -> Col1 based upon the IDs being the same on Col2 and Col1 between different rows
I cannot fathom this further than:
select *
from table as t1
join table as t2 on t1.col2 = t2.col1
That query only does a single join but i'd like to keep joining for as long as it is successful to retrieve a sum of successful joins
It's not possible for me to manually write the joins because there could potentially be none, one or many joins
You can use recursive cte to achieve this.
Sample example
With recursive cte(id) as
(Select 1 as id from dual
Union all
Select id +1 from cte where id < 10)
Select * from cte;
Here values will recusively generate untill it reaches value of 10.
how to find duplicates on a table with three columns (col1,col2,col3) if ANY two of the columns have duplicate?
put in pseudo-query it would look like this:
If col1 and col2 are the same, then select
if col2 and col3 are the same, then select
if col1 and col3 are the same, then select
if col1,col2 and col3 are the same, then select
I don't want to use 'IF' because the number of columns are actually greater than 10 which would make the 'IF' query very tedious.
thanks.
Probably the best bet with MySQL is:
where col1 in (col2, col3, col4, . . . ) or
col2 in (col3, col4, . . . ) or
col3 in (col4, . . . ) or
. . .
N.B. I took your question to mean, that 2 rows are considered duplicates if two or more of their column values are equal. If you were just looking for duplicate values in columns for the same row, #GordonLinoff's answer is more appropriate
In MySQL booleans are actually represented as 0 or 1
For your three column example, the condition
(a.col1 = b.col1) + (a.col2 = b.col2) + (a.col3 = b.col3) >= 2
should do the trick
For example, assuming you have a unique id column:
SELECT *
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE (a.col1 = b.col1) + (a.col2 = b.col2) + (a.col3 = b.col3) >= 2
AND a.id != b.id /** Don't consider the same row */
)
UPDATE
I'm not surprised that you get a large time difference between 1k and 130k. I imagine the scale will be linear so 15s * 130/1 = 1950s, which is about 30 minutes for querying on the full table.
Also don't forget that for each row, the query is checking all the other rows for duplicates. This is why just fetching the whole table is faster.
I would hope that you only need to use this query as a one-off to identify the dupes. If not, it would point to some iffy database design and likely the table could be refactored to better suit its purpose. This is the XY Problem that #apokryfos is referring to in his comment on your question.
The above query will not allow the use of any indexes on the columns, due to the complicated condition.
You could potentially reach a result faster by using UNION ALL, assuming you have an individual index on some of the columns and id is the PK of the table.
SELECT base.*
FROM your_table base
JOIN (
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col1 = a.col1
AND b.id != a.id
)
UNION ALL
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col2 = a.col2
AND b.id != a.id
)
UNION ALL
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col3 = a.col3
AND b.id != a.id
)
) raw
ON raw.id = base.id
GROUP BY base.id
HAVING SUM(raw.col_match) >= 2
It may look hefty, but could easily be built dynamically in an application layer for your ten plus columns.
Bear in mind, if you have more duplicates than uniques, it may make sense to invert this logic.
I am getting data from a linked server, in which lets say I am having an identifier which I am joining with the identifier on my server and getting the data for it.
But the thing is identifier from Linked server contains some extra characters and while joining its not able to correctly join.
Can i do something like this that when I join, I will replace the identifies extra characters with space or NULL.
For ex.
Table 1
Col1 Col2
23rf name
24rf id
Table 2
Col1 Col2
23 name1
24 id1
SELECT
ta1.*,
ta2.*
FROM Table1 ta1
INNER JOIN Table2 ta2
ON ta1.Col1 = ta2.Col2
So this will give NULL
I want a query which can result the data by replacing "rf" to "" and join the two table, so that I can't get a NULL DataSet.
Second Approach:
Can I insert the data from one table to another table where while inserting, I can replace "rf" to "".
But, I do not know how to proceed for the above approach.
Please suggest.
You can do this by assigning an id to each of your tables using ROW_NUMBER. So, I used now row as their common field. See and try my queries below:
In SQL-SERVER:
SELECT ta1.Col1,ta1.Col2,ta2.Col1,ta2.Col2 FROM
(SELECT
ROW_NUMBER() OVER(ORDER BY Col1) AS Row,*
FROM Table1) AS ta1
INNER JOIN
(SELECT
ROW_NUMBER() OVER(ORDER BY Col1) AS Row,*
FROM Table2) AS ta2
ON ta1.Row=ta2.Row
In MYSQL:
SELECT ta1.Col1,ta1.Col2,ta2.Col1,ta2.Col2 FROM
(SELECT
#row_number1:=#row_number1+1 AS RowNumber1,
Col1,
Col2
FROM Table1, (SELECT #row_number1:=0)AS x ORDER BY Col1) AS ta1
INNER JOIN
(SELECT
#row_number2:=#row_number2+1 AS RowNumber2,
Col1,
Col2
FROM Table2, (SELECT #row_number2:=0)AS y ORDER BY Col1) AS ta2
ON ta1.RowNumber1=ta2.RowNumber2
I can apply this query only for one table and I want to apply it for 5 tables in a temporary table with making records in alphabetical order. Because it has freezing problem more then 5000 records and the solution is applying the records when it starts "a letter"
and after "b letter" .... to the end "z letter" for example
amanda
anabele
.
.
.
zeplin
zambia
the important thing is first letter should be in an alphabetical order
shortly I want to make a temporary table and applying the query in alphabeticak order on first letter.. How can I make it?
UPDATE
names INNER JOIN
(SELECT n1.id, n1.name, count(n2.id)+1 cnt
FROM names n1 INNER JOIN names n2
ON n1.name=n2.name AND n1.id>n2.id
GROUP BY n1.id, n1.name) s
ON names.id = s.id
SET
names.name = CONCAT(names.name, '.', s.cnt)
If you want to gather data from multiple tables, I would use UNION or - if you do not want/need to filter out duplicates - UNION ALL (which should be a bit faster).
Example:
SELECT col1, col2
FROM table1
UNION ALL
SELECT col3, col4
FROM table2
If your want it sorted, this is the way (if I remember correctly)
SELECT col1 as column1, col2 as column2
FROM table1
UNION ALL
SELECT col3 as column1, col4 as column2
FROM table2
ORDER BY column1
If you are facing performance issues, consider making your temp table an actual table. You can 'clean' it before (re)filling by simply truncating it and then you can use an insert query per table you want to add. No need to sort it since you can just do a SELECT/ORDER BY on your table.
If the above doesn't help you, perhaps you could add an example of what data you start from and the desired result?
Are you looking for something like this?
CREATE TEMPORARY TABLE temp_names LIKE names;
INSERT INTO temp_names
SELECT id, CONCAT(name, COALESCE(CONCAT('.', rnum), '')) name
FROM
(
SELECT id, name, #n := IF(#g = name, COALESCE(#n, 0) + 1, NULL) rnum, #g := name
FROM names
ORDER BY name
) q;
What's wrong with my sql query? I am trying to use a Join and at the same time a UNION to get all table from another table while joining other tables together based on a relationship ..
However I get the following error:
"The used SELECT statements have a different number of columns"
My query:
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp
,b.AlarmingStatus
,b.STxModel
,c.GroupID
FROM STxMessage a
JOIN STx b ON b.ESN = a.ESN
JOIN GroupInfo c ON b.GroupID = c.GroupID
WHERE b.STxModel = 190
AND a.AlarmsChecked="y"
AND c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN , d.UnixTime, d.Payload, d.Timestamp FROM STxMessageArchive d
The error message says it all.
When using UNION, the columns return by the combined SELECT statement must be the same, eg.
SELECT col1, col2, col3 FROM table1
UNION
SELECT col1, col2, col3 FROM table2
if the columns do not match, you can still combine it provided that you have to provide dummy data for the column, eg
SELECT col1, col2, col3 FROM table1
UNION
SELECT col1, col2, '' AS col3 FROM table2
so in your query, it should look like this
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp ,
b.AlarmingStatus, b.STxModel, c.GroupID
FROM STxMessage a
INNER JOIN STx b
ON b.ESN = a.ESN
INNER JOIN GroupInfo c
ON b.GroupID = c.GroupID
WHERE b.STxModel = 190 AND
a.AlarmsChecked="y" AND
c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN, d.UnixTime, d.Payload, d.Timestamp,
NULL AS AlarmingStatus, NULL AS STxModel, NULL AS GroupID
FROM STxMessageArchive d
hi this are the extra columns in your first query
,b.AlarmingStatus
,b.STxModel
,c.GroupID
you need this same columns in second query to do union or you need to remove this column to do union operation
Your first query is selecting 7 columns where as the second query is only selecting 4. You need to make sure the second query is selecting the same number of columns as the first to make the Union All work.
SELECT a.ESN, a.UnixTime, a.Payload, a.Timestamp
,b.AlarmingStatus
,b.STxModel
,c.GroupID
FROM STxMessage a
JOIN STx b ON b.ESN = a.ESN
JOIN GroupInfo c ON b.GroupID = c.GroupID
WHERE b.STxModel = 190
AND a.AlarmsChecked="y"
AND c.AlertsMasterSwitch="on"
UNION ALL
SELECT d.ESN , d.UnixTime, d.Payload, d.Timestamp, 'null' as AlarmingStatus,
'null' as STxModel, 'null' as GroupID FROM STxMessageArchive d
As the error says, the first part has 7 columns, and the second part has only 4. An unions needs to have the same columns on both sides. Either remove
b.AlarmingStatus ,b.STxModel ,c.GroupID
from the first part, or add (even bogus) columns in the second part.