SQLite: Number rows of query output - sqlite

I am learning SQLite and I am currently posing the question whether there is a simple way of adding a sequential numbering to the output of a query. Underneath, I provide an example of what I am trying to achieve.
For instance, I have the following query:
SELECT
splTicker AS 'Ticker',
count(splTicker) AS '# of Splits'
FROM Splits
GROUP BY splTicker
ORDER BY count(splTicker) DESC, splTicker ASC;
The output of this query is as follows:
bash-3.2$ sqlite3 myShares < Queries/Split.sql
Ticker # of Splits
---------- -----------
AI.PA 7
ASML.AS 3
BN.PA 3
ALTR.LS 2
BOKA.AS 2
DG.PA 2
...
SON.LS 1
SU.PA 1
SW.PA 1
TEC.PA 1
UMI.BR 1
VIV.PA 1
VPK.AS 1
I am trying to add a sequential number to the rows to obtain the following output:
# Ticker # of Splits
-- ---------- -----------
1 AI.PA 7
2 ASML.AS 3
3 BN.PA 3
4 ALTR.LS 2
5 BOKA.AS 2
6 DG.PA 2
...
Currently, I use a workaround and add the row numbers post-query in Perl. I am posing the question whether I could do this directly in SQLite. The idea seems simple, but I have not found a solution yet. Any help would be appreciated.
Best regards,
GAM

Try this:
SELECT
(SELECT COUNT(*)
FROM Splits AS s2
WHERE s2.splTicker <= s1.splTicker) AS '#',
splTicker AS 'Ticker',
count(splTicker) AS '# of Splits'
FROM Splits s1
GROUP BY s1.splTicker
ORDER BY count(s1.splTicker) DESC, s1.splTicker ASC;

Related

Getting output of duplicates and not the same as another column

Example database:
column1 | column2
--------+---------
1 | 1
2 | 1
3 | 3
4 | 3
5 | 5
6 | 7
7 | 3
I would like to get an output of
2 | 1
4 | 3
7 | 3
This is the query I use:
SELECT
column2, COUNT(*) c
FROM
table
GROUP BY
column2
HAVING
c > 1
which returns:
1 | 2
3 | 3
I would like to take it a step further:
SELECT *
FROM table
WHERE (column1 != column2 AND having count(*) > 1)
The first SQL
SELECT column2, COUNT(*) c
FROM table
GROUP BY column2
HAVING c > 1
returns a nice list of the column2 values you want. You will need a self-JOIN and get the column1's that go with. That will require using table aliases. You could try it this way
SELECT T1.column1, T1.column2
from table T1
JOIN (SELECT column2, count(*) c
FROM table
GROUP BY column2
HAVING c > 1) T2 ON T2.column2 = T1.column2
WHERE T1.column1 <> T2.column2
[Author's note] This is not the answer as originally written. The stack help re: editing says:
Edits are expected to be substantial and to leave the post better than
you found it. Common reasons for edits include:
To fix grammar and spelling mistakes
To clarify the meaning of the post (without changing that meaning)
To include additional information only found in comments, so all of the information relevant to the post is contained in one place
To correct minor mistakes or add updates as the post ages
To add related resources or hyperlinks
The edit does not meet any of the criteria. However, on the same page it says:
If you are not comfortable with the idea of your contributions being
collaboratively edited by other trusted users, this may not be the
site for you.
So be it.

SQL - Select top n grouped by multiple fields, ordered by count

I am attempting to find the top n records when grouped by multiple attributes. I believe it is related to this problem, but I am having difficulty adapting the solution described to my situation.
To simplify, I have a table with columns (did is short for device_id):
id int
did int
dateVal dateTime
I am trying to find the top n device_id's for each day with the most rows.
For example (ignoring id and the time part of dateTime),
did dateVal
1 2017-01-01
1 2017-01-01
1 2017-01-01
2 2017-01-01
3 2017-01-01
3 2017-01-01
1 2017-01-02
1 2017-01-02
2 2017-01-02
2 2017-01-02
2 2017-01-02
3 2017-01-02
Finding the top 2 would yield...
1, 2017-01-01
3, 2017-01-01
2, 2017-01-02
1, 2017-01-02
My current naive approach is only giving me the top 2 across all dates.
--Using SQLite
select date(dateVal) || did
from data
group by date(dateVal), did
order by count(*) desc
limit 2
I'm using the concatenation operator so that I can later extract the rows.
I am using SQLite, but any general SQL explanation would be appreciated.
Similarly to this question, define a CTE that computes all device counts for your desired groups, then use it in a WHERE ... IN subquery, limited to the top 2 devices for that date:
WITH device_counts AS (
SELECT did, date(dateval) AS dateval, COUNT(*) AS device_count
FROM data
GROUP BY did, date(dateval)
)
SELECT did, date(dateval) FROM device_counts DC_outer
WHERE did IN (
SELECT did
FROM device_counts DC_inner
WHERE DC_inner.dateval = DC_outer.dateval
GROUP BY did, date(dateval)
ORDER BY DC_inner.device_count DESC LIMIT 2
)
ORDER BY date(dateval), did
I tested the query using sql server
select top 2 did, dateVal
from (select *, count(*) as c
from test
group by did,dateVal) as t
order by t.c desc

walking list using cte

Still learning SQL :)
This time I'd like to a 'linked list' walk from a table I guess using CTE.
Despite all the example on the web I could not find one simple example I could start from then peek and poke from there.
Here is my table
create table yo (id integer, nx integer)
select * from yo
id nx
---------- ----------
1 5
2 4
3 7
4 9
5 3
6 0
7 0
8 6
9 8
I'd like to get a list of 'id','nx' from yo following the next link 'nx' given a start 'id'
So a start 'id' of 1 would produce
id nx
---------- ----------
1 5
3 7
5 3
7 0
Note that 0 is a end marker.
I can't find the magic SQL for doing this
Thanx in advance
Cheers,
Phi
The first row of the list is easy:
SELECT id, nx
FROM yo
WHERE id = 1
If the nx column of the previous entry is available as list.nx, the next entry can be returned with this query:
SELECT yo.id, yo.nx
FROM yo
JOIN list ON yo.id = list.nx
Then just plug these together:
WITH RECURSIVE list(id, nx) AS (
SELECT id, nx
FROM yo
WHERE id = 1
UNION ALL
SELECT yo.id, yo.nx
FROM yo
JOIN list ON yo.id = list.nx
)
SELECT * FROM list
(This stops automatically because there is no row where id is zero; otherwise, you could add a WHERE list.nx != 0.)

Filtering in Oracle based on a group of values contained in a list of values

I have following two tables:
ID_PERSON NAME
-----------------
1 John
2 Joe
3 Peter
ID_PERSON ID_SPECIALIZATION
------------------------------
1 5
1 6
1 7
2 5
2 1
3 6
3 10
I need to filter data based on group of ids ID_SPECIALIZATION that will be provided. For example
I want to display only those persons who has specialization in 5 and 6 so it will return only first person. In ASP.NET Web form there will be two listboxes, left and right button, in first LB there will be all possible specializations and user will choose some of them to second LB as filtering options. I have no idea how to put this filtering condition in sql query. Thanks for help.
You could use the following:
SQL> SELECT p.id_person, p.NAME
2 FROM person p
3 JOIN person_spe s ON p.id_person = s.id_person
4 WHERE id_specialization IN (5, 6)
5 GROUP BY p.id_person, p.NAME
6 HAVING COUNT(*) = 2;
ID_PERSON NAME
---------- -----
1 John
One way to do it:
SELECT
ID_PERSON
, NAME
FROM
Person AS p
WHERE EXISTS
( SELECT *
FROM
PersonSpecialization AS ps
WHERE ps.ID_PERSON = p.ID_PERSON
AND ps.ID_SPECIALIZATION = 5
)
AND EXISTS
( SELECT *
FROM
PersonSpecialization AS ps
WHERE ps.ID_PERSON = p.ID_PERSON
AND ps.ID_SPECIALIZATION = 6
)
SELECT d1.id_person, d1.name FROM tbl_table1 d1
INNER JOIN tbl_table2 d1
ON d1.ID_PERSON=d2.ID_PERSON
WHERE ID_SPECILIZATION = ?
Theres the query but I'm not sure how asp.net works and passing in the value. It might be work looking up bind variables which allows you to use place holders in the sql which oracle then caches the query and just uses the values that you pass in at run tuime using EXECUTE IMMEDIATE.

generate 6 numbers between 1 and 2 in a 2:1 ratio in SQL or PL/SQL

how can i generate 6 numbers between 1 and 2 where 4 of the numbers will be 1 and the other 2 will be 2 in a random order i.e.
results
1
2
1
1
1
2
and also in a different ratio i.e. 3:2:1 for numbers between 1 and 3 for 12 numbers
i.e.
results
1
1
2
3
1
2
1
3
1
1
3
3
results don't have to be in this order but in the ratios as above in oracle SQL or PL/SQL
To get the ratios perfect you could do something like this - generate all the numbers, then sort in random order:
SELECT r
FROM (SELECT CASE
WHEN ROWNUM <=4 THEN 1
ELSE 2
END AS r
FROM DUAL
CONNECT BY LEVEL <= 6)
ORDER BY DBMS_RANDOM.value;
R
----------------------
2
1
1
2
1
1
I think this will work in straight SQL; it's horrifically inefficient, and a PL/SQL one might be less so. It's also completely static; differing ratios call for a different number of values selected.
select value
from (
select mod(value, 2) + 1 as value,
row_number() over (partition by
case mod(value, 2) = 1
then 1
else 0
end) as twos_row,
row_number() over (partition by
case mod(value, 2) = 0
then 1
else 0
end) as ones_row
from (select dbms_crypto.randominteger as value
from dba_objects
order by object_id
)
)
where twos_rows <= 2
or ones_rows <= 4
The inner-most select grabs a big stack of random numbers. The next query out determines whether that random value would be a 2 or a 1 by mod'ing the earlier random value. The last level of nesting just filters out all the rows after the correct number of that type of row has been returned.
This is untested and fragile. If you need a solution that's reliable and performance, I'd recommend PL/SQL, where you
loop
pick off random numbers
determine what partition in your set of values they'd fit into
keep them if that partition hasn't been satisfied
exit when all partitions have been satisfied.

Resources