I am working through an SAP textbook to learn more about the systems and how to interact with them for work. I am very new to SAP and I don't really understand this question. Could someone please explain and help me understand what is going on here?
Some rows in valueTable have corresponding rows in textTable with language EN, for example ID 1, while others have not, for example ID 2.
You are asked to write a SELECT statement that joins the two tables such that only the values with English text are selected, i.e. this should be the result:
id | value1 | value2 | text
---| ------ | ------ | ------
1 | A | 11 | Foobar
3 | C | 13 | bar
The question can be answered with basic understanding of SQL, esp. JOINs, and does not require specific ABAP know how.
Related
I am facing an issue where a data supplier is generating a dump of his multi-tenant databases in a single table. Recreating the original tables is not impossible, the problem is I am receiving millions of rows every day. Recreating everything, every day, is out of question.
Until now, I was using SSIS to do so, with a lookup-intensive approach. In the past year, my virtual machine went from having 2 GB of ram to 128, and still growing.
Let me explain the disgrace:
Imagine a database where users have posts, and posts have comments. In my real scenario, I am talking about 7 distinct tables. Analyzing a few rows, I have the following:
+-----+------+------+--------+------+-----------+------+----------------+
| Id* | T_Id | U_Id | U_Name | P_Id | P_Content | C_Id | C_Content |
+-----+------+------+--------+------+-----------+------+----------------+
| 1 | 1 | 1 | john | 1 | hello | 1 | hello answer 1 |
| 2 | 1 | 2 | maria | 2 | cake | 2 | cake answer 1 |
| 3 | 2 | 1 | pablo | 1 | hello | 1 | hello answer 3 |
| 4 | 2 | 1 | pablo | 2 | hello | 2 | hello answer 2 |
| 5 | 1 | 1 | john | 3 | nosql | 3 | nosql answer 1 |
+-----+------+------+--------+------+-----------+------+----------------+
the Id is from my table
T_Id is the "tenant" Id, which identifies multiple databases
I have imagined the following possible solution:
I make a query that selects non-existent Ids for each table, such as:
SELECT DISTINCT n.t_id,
n.c_id,
n.c_content
FROM mytable n
WHERE n.id > 4
AND NOT EXISTS (SELECT 1
FROM mytable o
WHERE o.id <= 4
AND n.t_id = o.t_id
AND n.c_id = o.c_id)
This way, I am able to select only the new occurrences whenever a new Id of a table is found. Although it works, it may perform badly when working with 100s of millions of rows.
Could anyone share a suggestion? I am quite lost.
Thanks in advance.
EDIT > my question is vague
My final intent is to rebuild the tables from the dump, incrementally, avoiding lookups outside the database. Every now and then I am gonna run a script that will select new tenants, users, posts and comments and add them to their corresponding tables.
My previous solution worked as follows:
Cache the whole database
For each new row, search for the columns inside the cache
If it doesn't exist, then insert it
I know it sounds dumb, but it made sense as a new developer working with ETLs
First, if you have a full flat DB dump, I'll suggest you to work on your file before even importing it in your DB (low level file processing is pretty cheap and nearly instantaneous).
From Removing lines in one file that are present in another file using python you can remove all the already parsed line since your last run.
with open('new.csv','r') as source:
lines_src = source.readlines()
with open('old.csv','r') as f:
lines_f = f.readlines()
destination = open('diff_add.csv',"w")
for data in lines_src:
if data not in lines_f:
destination.write(data)
destination.close()
This take less than five second to work on a 900Mo => 1.2Go dump. With this you'll only work with line that really make change in one of your new table.
Now you can import this flat DB to a working table.
As you'll have to search the needle in each line, some index on the ids may by a good idea (go to composite index that use your Tenant_id first).
For the last part, I don't know exactly how your data look, can you have some update to do ?
The Operators - EXCEPT and INTERSECT can help you too with this kind of problem.
I have two tables in a SQL Server DB. One table BusinessOperations has various information about this business object, the other table OperationType is purely a bitwise flag table that looks like this:
| ID | Type | BitFlag |
| 1 | Basic-A | -2 |
| 2 | Basic | -1 |
| 3 | Type A | 0001 |
| 4 | Type B | 0002 |
| 5 | Type C | 0004 |
| 6 | Type D | 0008 |
| 7 | Type E | 0016 |
| 8 | Type F | 0032 |
The BitFlag column is a varchar column, the bitflags were inserted as '0001' as an example. In the BusinessOperations table, there's a column where the application that uses these tables updates it based on what is selected in the application's UI. As an example, I have one type which has the Basic,Type A, and Type B types selected. The column value in BusinessOperations is 3.
Based on this, I am trying to write a query which will show me something like this:
| ID | Name | Description | OperationType |
| 1 | Test | Test | Basic, Type A, Type B |
Here is the actual layout of the BusinessOperations table (Basic-A and Basic are bit columns:
| ID | Name | Description | Basic-A | Basic | OperationType |
| 1 | Test | Test | 0 | 1 | 3 |
There is nothing that relates these two tables to each other, so I cannot perform a join. I am very inexperienced with bitwise operations and am at a loss on how exactly to structure my select query which is being used to analyze this data. I feel like it needs a STUFF or CASE, but I don't know how I can get this to just show the types and not just the resultant BitFlag.
SELECT ID, Name, Description, OperationType
FROM OperationType
ORDER BY ID
Since you're storing the flag in OperationType as a VARCHAR, the first thing you need to do to is CONVERT or CAST the string to a number so we can do proper bitwise comparisons. I'm slightly unfamiliar with SQL Server, but you may need to remove the leading zeroes before the cast. Thus, the OperationType column in our desired SQL will look something like
CONVERT(INT, BitFlag)
Then, comparing that to our OperationType column would look something like
CONVERT(INT, BitFlag) & OperationType
The full query would look something like (forgive my lack of SQL Server expertise again):
SELECT bo.ID, bo.Name, bo.Description, ot.Type
FROM BusinessOperations AS bo
JOIN OperationType AS ot
ON CONVERT(INT, ot.BitFlag) & OperationType <> 0
The above query will effectively get you a list of the OperationTypes. If you absolutely need them on one line, see other answers to learn how to emulate something like GROUP_CONCAT in SQL Server. Disclaimer: Joining on a bitmask gives no guarantee of performance.
The other problem this answer does not solve is that of your legacy Basic and Basic-A fields. Personally, I'd do one of two things:
Remove them from the OperationType table and have the application tack the two on, based on the Basic and Basic-A columns as appropriate.
Put Basic and Basic-A as their own, positive flags in the OperationType table, and have the application populate the legacy columns as well as the OperationType column as appropriate.
As Aaron Bertrand has said in the comments, this really isn't an issue for Bitmasking at all. Having a many-many table that associates BusinessOperations.ID to OperationType.ID would solve all your problems in a much better way.
In the BusinessOperations table the Basic-A and Basic field are bit fields which is just another way of saying the value can only be a 1 or 0. Think of it like a boolean value True/False. So, in your query you can check each of those to determine whether to include 'Basic-A' and 'Basic' or not.
The OperationType is probably an id which you can lookup in the OperationsType table to get the Type and BitFlag. Without understanding your data completely it looks as if you could do a join for that part. Hopefully that is in the right general direction. If not, let me know.
I am dealing with more than 25 tables which having association and I need to return a simple array/cursor from my stored procedure.
To make simple my question I am providing below example:-
For mentioned below scenario I want to add subjects against each student means in existing emp_curr I want to add result of sub_cur.
cursor emp_curr is
select st_id,st_name,st_surname from student;
BEGIN
FOR n IN emp_curr LOOP
DECLARE
cursor sub_cur is
select sub_id,subject from student_subjects where st_id_fk=n.st_id;
BEGIN
FOR c IN sub_cur LOOP
-- Here I want to store sub_cur values in existing emp_curr
end loop;
END;
end loop;
END;
Final Output
|-----------|--------------|----------|---------------|-
|Student ID | Student Name |Student ID|Student subject|
|-----------|--------------|----------|---------------|-
| 1 | prashant | 2 | Maths |
| 1 | prashant | 4 | English |
| 1 | prashant | 3 | Science |
|-----------|--------------|----------|---------------|-
| 2 | shailndra | 1 | Hindi |
| 2 | shailndra | 5 | Geo |
| 2 | shailndra | 7 | Chemical |
|-----------|--------------|----------|---------------|-
It will be great if you can help me as I have already spent 4 hours and its gone in vain.
Prashant Thakre, how are you? Perhaps I misunderstood your question, so I will explain myself and hopefully, help you. The first thing I realized from your scenario is it's odd. You cannot change an Oracle cursor structure once you have declared it. More than that, I don't see the need to implement such a procedure. You use two columns from the table STUDENT, am I right? Then, you need two more columns added to your data set, those two coming from the table STUDENT_SUBJECTS. And it seems to exist some referential integrity between those tables, because you have an equijoin condition in the second cursor's query ( ...where st_id_fk=n.st_id)
So, I wonder, why don't you open the first cursor setting the following query, so you don't need to add those columns "by hand"?
select s.st_id,s.st_name,s.st_surname,sb.sub_id,sb.subject
from student s,student_subjects sb
where s.st_id=sb.st_id_fk
Using that query, you have want you are looking for, what you are needing.
Again, maybe I misunderstood your issue, but I really want to help you. So, give more ight"on the subject if that query is not what you need.
Best regards.
Jorge.
I have a relationships table, the table looks something like this
------------------------
| client_id | service_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 4 |
| 1 | 7 |
| 2 | 1 |
| 2 | 5 |
------------------------
I have a list of new permissions I need to add, what I'm doing right now is, for example, if I have to add new permissions for the client with id 1, i do
DELETE FROM myTable WHERE client_id = 1
INSERT INTO ....
Is there a more efficient way I can remove only the ones I won't insert later, and add only the new ones?
yes, you can do this but in my humble opinion, it's not really sql dependent subject. actually it depends on your language/platform choice. if you use a powerful platform like .NET or Java, there are many database classes like adapters, datasets etc. which are able to take care of things for you like finding the changed parts, updating/inserting/deleting only necessery parts etc.
i prefer using hibernate/nhibernate like libraries. in this case, you don't even need to write sql queries most of the time. just do the things at oop level and synchronize with the database.
If you put the new permissions into another table, you could do something like:
DELETE FROM myTable WHERE client_id in (SELECT client_id FROM tmpTable);
INSERT INTO myTable AS (SELECT client_id, service_id FROM tmpTable);
You are still taking 2 passes, but you are doing them all at once instead of one at a time.
Suppose I am storing events associated with users in a table as follows (with dt standing in for the timestamp of the event):
| dt | user | event |
| 1 | 1 | A |
| 2 | 1 | D |
| 3 | 1 | B |
| 4 | 1 | C |
| 5 | 1 | B |
| 6 | 2 | B |
| 7 | 2 | B |
| 8 | 2 | A |
| 9 | 2 | A |
| 10 | 2 | C |
Such that we could say:
user 1 has an event-sequence of ADBCB
user 2 has event-sequence BBAAC
The types of questions I would want to answer about these users are very easy to express as regular expresions on the event-sequences, e.g. "which users have an event-sequence matching A.*B?" or "which users have an event-sequence matching A[^C]*B[^C]*D?" etc.
What would be a good SQL technique or operator I could use to answer similar queries over this table structure?
Is there a way to efficiently/dynamically generate a table of user-to-event-sequence which could then be queried with regex?
I am currently looking at using Postgres, but I am curious to know if any of the bigger DBMS's like SQLServer or Oracle have specialized operators for this as well.
With Postgres 9.x this is actually quite easy:
select userid,
string_agg(event, '' order by dt) as event_sequence
from events
group by userid;
Using that result you can now apply a regular expression on the event_sequence:
select *
from (
select userid,
string_agg(event, '' order by dt) as event_sequence
from events
group by userid
) t
where event_sequence ~ 'A.*B'
With Postgres 8.x you need to find a replacement for the string_agg() function (just google for it, there are a lot of examples out there) and you need a sub-select to ensure the ordering of the aggregate as 8.x does support an order by in an aggregate function.
I'm not at a computer to write code for this answer, but here's how I would go about a RegEx-based solution in SQL Server:
Build a string from the resultset. Something like http://blog.sqlauthority.com/2009/11/25/sql-server-comma-separated-values-csv-from-table-column/ should work if you omit the comma
Run your RegEx match against the resulting string. Unfortunately, SQL Server does not provide this functionality natively, however, you can use a CLR function for this purpose as described at http://www.ideaexcursion.com/2009/08/18/sql-server-regular-expression-clr-udf/
This should ultimately provide you with the functionality in SQL Server that your original question requests, however, if you're analyzing a very large dataset, this could be quite slow and there may be better ways to accomplish what you're looking for.
For Oracle (version 11g R2):
By chance if you are using Oracle DB 11g R2, take look at listagg. The below code should work, but I haven't tested. The point is: you can use listagg.
SQL> select user,
2 listagg( event, '' )
3 within group (order by dt) events
4 from users
5 group by user
6 order by dt
7 /
USER EVENTS
--------- --------------------
1 ADBCB
2 BBAAC
In prior versions you can do with CONNECT BY clause. More details on listagg.