SQLite Relational Database Query in Ruby - ruby

I have 2 SQLite databases, Salesmen and Sales. Here's what the original CSV files looked like, but I've already put them in SQLite (just so you can see how the tables are layed out):
Salesmen Table
id, name
1, john
2, luther
3, bob
Sales Table
id, salesmen_id, sales_amount
1, 1, 100
2, 3, 20
3, 2, 35
4, 3, 25
5, 1, 55
6, 2, 200
7, 2, 150
My question is how do I write a function in ruby that will return all the Salesmen names, sorted by their total sales amount? I know this requires using a join, but I'm not entirely sure how the query should look like.
I want the new table to look like this:
New Table
name, total_sales
luther, 385
john, 155
bob, 45
The new sqlite query should be in this format:
$db.execute %q{
SELECT account_name, units, unit_price
FROM accounts, positions
...
}
Thanks in advance

I think this is what you want
SELECT name, sum(sales_amount)
FROM salesmen INNER JOIN sales on sales.salesmen_id = salesmen.id
GROUP BY salesmen_id

Related

Oracle. How to exp/imp data from one DB to another which already has data?

I have one Oracle DB with ~40 tables. Some of them have IDs = 1, 2, 3, 4, 5... and constraints.
Now I want to "copy" this data from all tables to another Oracle DB which already has the same tables.
The problem is that another DB also has records (can be the same IDs = 1, 2, 3, 77, 88...) and I don't want to lose them.
Is there some automated way to copy data from one table to another with IDs shifting and constraints?
1, 2, 3, 77, 88 +
**1, 2, 3, 4, 5**
=
1, 2, 3, 77, 88, **89, 90, 91, 92, 93**
Or I need to do it by myself?
insert into new.table
select new.sequence_id.nextval, t.* from old.table t
save new.id - old.id mapping and etc etc etc for all 40 tables?
That's a bit dirty solution but if all IDs are numeric you can first update old IDs to negative number ID = -1 * ID (or just do it in select statement on the fly) then do insert. In that case you have all your IDs consistent, constraints are valid and they can live together with new data.
Firs, you need expdp, is second you ned remap schema new schema name in impdp

Query to display rows from a table related to certain number of days in Oracle

I'm a newbie to DB and I've a question regarding displaying contents from a table based on date.
How can I search for all the entities from EMPLOYEE table which matches certain value in EmpPayScaleID and +/- 3 days of EmpPayDate
For example,
I need to print all the values form EMPLOYEE table where EmpPayScaleId is 1001 and EmpPayDate should be +/- 3 days from 01-AUG-17 (should show records from 29-JUL-17 to 04-SEP-17)
I tried this:
SELECT * FROM EMPLOYEE
WHERE EmpPayScaleId = 1001
AND EmpPayDate in ADD_MONTHS(01-Aug-17, -3, dd-mm-yy)
AND EmpPayDate in ADD_MONTHS(01-Aug-17, 3, dd-mm-yy);
Correction:
SELECT * FROM EMPLOYEE
WHERE EmpPayScaleId = 1001
AND EmpPayDate in ADD_MONTHS(01-Aug-17, -3, 'DD-MON-YY')
AND EmpPayDate in ADD_MONTHS(01-Aug-17, 3, 'DD-MON-YY');
This shows nothing. Where was my mistake?
Is this a correct query?
Edit:
It shows invalid number of arguments when I use ADD_MONTHS(01-AUG-17, 3, 'DD-MON-YY')
The date in your query has been specified incorrectly.
The following where clause is enough:
...
WHERE EmpPayScaleId = 1001
AND to_date('01-Aug-17','DD-MON-YY') between EmpPayDate-3
and EmpPayDate+3;

linq order by from second table count

I have lets say two tables:
Student(id, name);
Class (id, name, student_id);
how I can select all students, but ordered by classes count?
Students:
1, "John"
2, "Andrew"
Classes:
1, french, 1
2, french, 2
3, Spanish, 1
4, English, 1
It should order:
John
Andrew
Right now I get students:
return entites.students.Include(w=>w.classes).ToList();
Order part is missing...
EDIT
Great, it works, but how it should looks, when classes table is in schools table and I want to get students ordered by schools count?
Students (id, name);
Classes (id, name, students_id);
Schools (id, name, classes_id);
Students:
1, "John"
2, "Andrew"
Classes:
1, french, 1
2, french, 2
3, Spanish, 1
4, English, 1
5, English, 2
Schools:
1, "Primary school", 1
2, "Secondary school", 2
3, "Another school", 5
It should give me:
Andrew
John
Assuming your file has a
using System.Linq;
above the namespace directive, you can do:
entities.students.Include(s => s.classes).OrderBy(s => s.classes.Count());

Show report horizontally with SQL or PL/SQL

I am developing a report which should display the data horizontally.
What must be shown is the following:
email#1.com 12/09/2013 11/09/2013 10/09/2013 09/09/2013...
email#2.com 22/03/2013 21/03/2013 12/02/2013 02/01/2013...
Well, I have these data organized in two tables:
Member and Report.
The Member table has the email address and the Report table has dates, and each email can have many different dates.
I can easily retrieve that information vertically:
SELECT M.EMAIL, R.LAST_OPEN_DATE
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120;
However to show the results horizontally is complicated, anyone have a tip or know how I can do this?
I'm using Oracle 11g.
You can get the dates into columns with pivot:
SELECT *
FROM (
SELECT M.EMAIL, R.LAST_OPEN_DATE,
ROW_NUMBER() OVER (PARTITION BY M.MEMBER_ID
ORDER BY R.LAST_OPEN_DATE DESC) AS RN
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120
)
PIVOT (MIN(LAST_OPEN_DATE) FOR (RN) IN (1, 2, 3, 4, 5, 6, 7, 8));
SQL Fiddle.
Essentially this is assigning a number to each report date for each member, and then the pivot is based on that ranking number.
But you'd need to have each of the possible number of days listed; if you can have up to 240 report dates, the PIVOT IN clause would need to be every number up to 240, i.e. IN (1, 2, 3, ..., 239, 240), not just up to eight as in that Fiddle.
If you ever had a member with more than 240 dates you wouldn't see some of them, so whatever high number you pick would have to be high enough to cover every possibility, now and in the foreseeable future. As your query is limited to 120 days, even 240 seems quite high, but perhaps you have more than one per day - in which case there is no real upper limit.
You could potentially have to format each date column individually, but hopefully your reporting layer is taking care of that.
If you just wanted to perform string aggregation using the multiple dates for each email, in you could do this in 11g:
SELECT M.EMAIL,
LISTAGG(TO_CHAR(R.LAST_OPEN_DATE, 'DD/MM/YYYY'), ' ')
WITHIN GROUP (ORDER BY R.LAST_OPEN_DATE DESC)
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120
GROUP BY M.EMAIL;
EMAIL DATES
-------------------- -------------------------------------------
email#1.com 12/04/2014 11/04/2014 10/04/2014 09/04/2014
email#2.com 12/05/2014 02/04/2014 22/03/2014 21/03/2014
SQL Fiddle.
Which is OK for a text report, but not if this query is feeding into a reporting tool.
First of all, number of columns in a query is determined before hand and can't be adjusted by the data. To overcome that, you might be interested in dynamic query
But, in simple static case, you will need to use PIVOT construction.
As a first step, you will need to assign rows to the columns
select EMAIL, row_number() over (partition by email order by last_date) col
from yourtable
then you add "magic" PIVOT:
<your query>
PIVOT
(
max(last_date)
for col in (1, 2, 3, ..., 240)
)

Versioning normalized Data in Oracle

I'm trying to find a good way to check if data I'm given through a bulk load (SQLLoader) already exists in my data set so I don't load it again.
Currently we have a set up like this,
TableA
col1, col2, bulkLoadName
This table would contain data like,
col1, col2, bulkLoadName
"Joe", 35, "Load1"
"Tim", 65, "Load1"
"Ray", 95, "Load1"
"Joe", 35, "Load2"
And I'd like to change it to,
TableA
PK, col1, col2
TableAtoBulkLoadName
PK, TABLEA_PK, BulkLoadName_PK
BulkLoadName
PK, bulkLoadName
Where the data would look like,
PK, col1, col2
1, "Joe", 35
2, "Tim", 65
3, "Ray", 95
PK, TABLEA_PK, BulkLoadName_PK
1, 1, 1
2, 2, 1
3, 3, 1
4, 1, 2
PK, bulkLoadName
1, "Load1"
2, "Load2"
This normalizes the data so I can easily check for a specific load without a string search and MOST importantly prevents me from loading duplicate data in the database just because something is defined again in a later load.
I'm having trouble deciding how I should implement the duplicate checks. I'm not well verse with SQL and need a solution that is in ORACLE 11g. I've looked and I've come up with 2 possible solutions...
Solution 1:
Use a temp table to store the bulk load and run a stored procedure once loaded to check.
Solution 2:
Use a MERGE clause on the TableA that adds new records to TableA or creates a new intersection record in TableAtoBulkLoadName if the record already exists.
My questions now that all of the background info is out there is what are the pro's and con's with these approaches? Is this kind of normalization normal? Are there standard ways of doing this sort of thing?
Thanks!
Strictly from a performance stand point, if you can do everything in one statement, that's usually better.
But as soon as you start to transform the data in various ways, I personally find that by using a staging table, the resulting code is a lot easier to read and modify.

Resources