Rewriting Outer apply to join for performance - sql-server-2008

Since I am not that familiar with Outer Apply, I am a bit lost with rewriting the one from my previous question to join. It worked well but not for large chunks of data. Any help with this appreciated.
Previous question

You might use the following approach:
Use a CTE to create a set and use ROW_NUMBER to number your calls.
ROW_NUMBER allows to specify the OVER() clause with a PARTITION BY and an ORDER BY part
This will return a list of your phone calls, where each phone number as a consecutive index in the order of EntryTime.
You can then use a self-join to find the corresponding previous row.
declare #table table (
PhoneNumber nvarchar(20),
EntryTime datetime
)
insert into #table values ('(321) 546-7842', dateadd(hour,-30,getdate()));
insert into #table values ('(321) 546-7842', dateadd(hour,-3,getdate()));
insert into #table values ('(251) 546-9442', dateadd(hour,-2,getdate()));
WITH cte AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY PhoneNumber ORDER BY EntryTime) AS CallIndex
,t.*
FROM #table t
)
SELECT *
FROM cte t1
LEFT JOIN cte t2 ON t1.PhoneNumber=t2.PhoneNumber AND t1.CallIndex=t2.CallIndex-1
ORDER BY t1.PhoneNumber, t1.EntryTime;

Related

Condtional select query if a value in coulmn is empty

I have a table
and I'm trying to write a select statement with ifnull condition for same type value like to get the result as shown in this table
Below is the sql I have tried -
SELECT
type,
memo,
IFNULL( memo, type = type) memo_all,
amount
FROM
table
But I get the same result as memo column in memo_all column with above query as can be seen in this table 3. Please find the sqlfiddle here with above query and table - http://sqlfiddle.com/#!9/55c43f
What am I missing here? Is there any alternative way to get the result as shown in table 2?
Just in case you are using a version of MySQL earlier than 8+, here is an alternative to Gordon's answer which doesn't use window functions:
SELECT
t1.type,
t1.memo,
t2.memo AS memo_all,
t1.amount
FROM yourTable t1
INNER JOIN
(
SELECT type, MAX(memo) AS memo
FROM yourTable
GROUP BY type
) t2
ON t1.type = t2.type;
SELECT t1.*, t2.memo memo_all
FROM `table` t1
JOIN `table` t2 USING (type)
WHERE t2.memo != '';
Solution which uses one source table copy:
SELECT `table`.*, #tmp := CASE WHEN memo = '' THEN #tmp ELSE memo END memo_all
FROM `table`, (SELECT #tmp := '') variable
ORDER BY type, memo DESC;
Use window functions:
SELECT type, memo,
max(memo) over (partition by type) as memo_all
amount
FROM table;
You want to "borrow" the value from another row. A simple scalar function is not going to do that. However, window functions provide this capability.
EDIT:
In older versions of MySQL, you can use a correlated subquery:
SELECT type, memo,
COALESCE(memo,
(SELECT t2.memo
FROM table t2
WHERE t2.type = t.type AND t2.memo IS NOT NULL
LIMIT 1
)
) as memo_all
amount
FROM table t;

Using CTE with same name several times in same query?

I've used the same cte several times in one script without issues, but I just wanted to double-check.
Let's say my script looks like this:
;with cte as
(
select provider, count(*) as 'rows_count'
from table1
) select *From cte
;with cte as
(
select fname, count(*) as 'totals'
from table_another
) select *From cte
;with cte as
(
select sum(sales) as 'total_sales
from table_yet_another
) select *From cte
Are there any issues to using the same cte with different select statements? Or should they have different names?
The name only needs to be unique within a single statement. So what you have is okay (if a bit confusing), but this would not be:
with cte as
(
select provider, count(*) as 'rows_count'
from table1
), cte as
(
select fname, count(*) as 'totals'
from table_another
) select *From cte
That is not the same query. A cte may only have one select statement. So that is three distinct statements.
The scope of a CTE is local to the statement. You can repeat them between different statements (but not twice in the same one). Although I would recommend using meaningful names for each one, just like you would with a table.

SQLite select all records and count

I have the following table:
CREATE TABLE sometable (my_id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING, number STRING);
Running this query:
SELECT * FROM sometable;
Produces the following output:
1|someone|111
2|someone|222
3|monster|333
Along with these three fields I would also like to include a count representing the amount of times the same name exists in the table.
I've obviously tried:
SELECT my_id, name, count(name) FROM sometable GROUP BY name;
though that will not give me an individual result row for every record.
Ideally I would have the following output:
1|someone|111|2
2|someone|222|2
3|monster|333|1
Where the 4th column represents the amount of time this number exists.
Thanks for any help.
You can do this with a correlated subquery in the select clause:
Select st.*,
(SELECT count(*) from sometable st2 where st.name = st2.name) as NameCount
from sometable st;
You can also write this as a join to an aggregated subquery:
select st.*, stn.NameCount
from sometable st join
(select name, count(*) as NameCount
from sometable
group by name
) stn
on st.name = stn.name;
EDIT:
As for performance, the best way to find out is to try both and time them. The correlated subquery will work best when there is an index on sometable(name). Although aggregation is reputed to be slow in MySQL, sometimes this type of query gets surprisingly good results. The best answer is to test.
Select *, (SELECT count(my_id) from sometable) as total from sometable

order by date in union query

SELECT *
FROM
(
SELECT case_id,diagnosis_title,updated
FROM tbl_case
order by updated desc
) as table1
UNION
select *
FROM
(
select image_id,image_title,updated
from tbl_image
order by updated desc
) as table2
how to display records with mixed order. currently tbl_Case records displaying first and tbl_image record displaying in second section.
i want to mix the output. ORDER BY should work for both table.
Any reason you're doing those outer select *? They're rather pointless, since they just reselect everything you've already selected.
With mysql unions, this is how you order the entire result set:
(SELECT case_id, diagnosis_title, ... FROM ...)
UNION
(SELECT image_id, image_title, ... FROM ...)
ORDER BY ...
With the bracketing in place as it is above, the order by will sort all the records from both results sets together, instead of sorting each individual query's results separately.
Try to simply your query.
SELECT case_id,diagnosis_title,updated
FROM tbl_case
UNION
select image_id,image_title,updated
from tbl_image
ORDER BY updated desc
You could do this, (I'm just guessing about data types)
CREATE TEMPORARY TABLE TempTable
(id int, title varchar(100), updated tinyint(1));
INSERT TempTable
SELECT case_id, diagnosis_title, updated FROM tbl_case ORDER BY updated DESC;
INSERT TempTable
SELECT image_id, image_title, updated FROM tbl_image ORDER BY updated DESC;
SELECT * FROM TempTable;
Obviously, this uses a temporary table instead of a union to achieve what I think you are asking for.

INSERT SELECT in MySQL with superfluous aggregate column

I'd like to do an insert select where the select statement has aggregate columns for use by a "HAVING" clause, but where I do not actually want those columns to be inserted. A simple example:
INSERT INTO table1 ( a )
SELECT a, MAX (b) AS maxb FROM table2
GROUP BY a
HAVING maxb = 1
Of course, this won't work because there are a different number of columns in the INSERT and the SELECT. Is there as simple way to make this work? I was hoping I could define some sort of null column in the INSERT field list, or something. I was hoping to avoid a subquery in my SELECT statement, although I could probably do it that way if necessary.
INSERT INTO table1 ( a )
SELECT a FROM (SELECT a, MAX (b) AS maxb FROM table2
GROUP BY a
HAVING maxb = 1) t
You can rewrite the query like this
INSERT INTO table1 ( a )
SELECT a FROM table2
GROUP BY a
HAVING MAX (b) = 1