Product: Sybase ASE 11/12/15/16
I am looking to update a Stored Procedure that gets called by different applications, so changing the application(s) isn't an option. What is needed is best explained in examples:
Current results:
type | breed | name
------------------------------------
dog | german shepherd | Bernie
dog | german shepherd | James
dog | husky | Laura
cat | british blue | Mr Fluffles
cat | other | Laserchild
cat | british blue | Sleepy head
fish | goldfish | Goldie
What I need is for the First column's data to be cleared on duplicates. For example, the above data should look like:
type | breed | name
------------------------------------
dog | german shepherd | Bernie
| german shepherd | James
| husky | Laura
cat | british blue | Mr Fluffles
| other | Laserchild
| british blue | Sleepy head
fish | goldfish | Goldie
I know I can do a cursor, but there are around 10,000 records and that doesn't seem proficient. Looking for a select command, don't want to change the data in the database.
After mulling over this, I found a solution that would work and not use a cursor.
select Type,breed,name
into #DontDisplay
from #MyDataList as a1
group by breed
Having breed= (select max(name)
from #MyDataList a2
where a1.breed= a2.breed)
order by breed, name
select n.Type,d.Breed,d.Name
from #MyDataList as d
left join #DontDisplay as n
on d.Breed= n.Breed and d.Name= n.Name
order by Breed
Works great and the solution was based on another solution Sybase SQL Select Distinct Based on Multiple Columns with an ID
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I would like to have some help on the best way to address a specific revision. I have the following SQL query:
SELECT * FROM PRODDTA.F4105
WHERE (COITM, COMCU) IN ((`"Set of Data 1"`))
AND (COLOCN, COLEDG) NOT IN ((`"Set of Data 2"`));
What I want to do is to revise if there is someway to merge these items in one:
SELECT * FROM PRODDTA.F4105
WHERE (COITM, COMCU, COLOCN, COLEDG) IN ((`"Set of Data 1 & 2"`));
Do you know if this is achievable?
Thanks a lot in advance,
This really depends on where Set of data 1 and Set of data2 come from and what their relationship is to each other, and I'm pressed to imagine a real world scenario where this would be a good idea.
A Set of Data here is really just a set of Records with Fields. These Fields have, inherently, a relationship to one another which is why they are present on a single Record.
Issue 1: The two sets contain data that don't relate to each other:
Set of Data1 could be completely disparate from Set of Data2 and so there is no way to say that they can be combined.
Imagine two sets:
Set1:
+-------+--------+
| color | animal |
+-------+--------+
| brown | dog |
| white | dog |
| black | dog |
| green | parrot |
| green | turtle |
| brown | turtle |
+-------+--------+
Set2:
+------------+--------+
| food | flavor |
+------------+--------+
| pepper | spicy |
| water | |
| grapefruit | bitter |
| lemon | sour |
| candy | sweet |
+------------+--------+
A queries WHERE clause:
WHERE (f1, f2) IN (SELECT color, animal FROM set1)
AND (f3, f4) IN (SELECT food, flavor FROM set2)
There's no good way to write this where we test (f1, f2, f3, f4) as there is no relationship between color | animal and food | flavor.
We could, if we were in crazytown, cross join the two sets to get their cartesian product yielding the same result set as the original query:
WHERE (f1, f2, f3, f4) IN (SELECT color, animal, food, flavor FROM set1, set2)
But now we have a subquery with an intermediate result set of set1 x set2 number of records. This is dumb for multiple reasons:
Indexes on the two sets are ignored
If set1 or set2 are more than a few records, you end up with a HUGE intermediate result set.
There is no relationship between these two sets, so it's crazy town to combine them just to make your SQL less characters.
There will be huge amounts of unnecessary system resources (CPU, Disk, I/O) used to build and store this intermediate result set resulting in a cumbersome slow query.
Any other developer upon seeing it will hunt you down and kill you. If they call me up, I'll provide the getaway car.
Issue 2: The two sets could have a relationship with one another, but changing your IN conditions into 1 causes records to drop.
Even if the two sets can be combined, you may still end up with results that differ from the original query. Imagine:
Set1:
+-------+--------+
| color | animal |
+-------+--------+
| brown | dog |
| white | dog |
| black | dog |
| green | parrot |
| green | turtle |
| brown | turtle |
+-------+--------+
Set 2:
+--------+-------------+
| animal | stink_scale |
+--------+-------------+
| turtle | 2 |
| parrot | 4 |
| dog | 5 |
| skunk | 10 |
+--------+-------------+
Table1:
+-------+--------+---------+-------------+
| color | animal | animal2 | stink_scale |
+-------+--------+---------+-------------+
| white | dog | dog | 5 |
| brown | dog | parrot | 4 |
| green | turtle | turtle | 2 |
+-------+--------+---------+-------------+
The query you want to change:
SELECT * FROM table1
WHERE (color, animal) IN (SELECT color, animal FROM Set1)
AND (animal2, stink_scale) IN (SELECT animal, stink_scale FROM set2);
This would yield 3 records as white | dog is in set1 and dog | 5 is in set as it brown | dog in set1 and parrot | 4 is in set2 and the same for the third record in table1.
BUT if we combine these two sets on their animal key:
SELECT set1.color, set1.animal, set2.animal as animal2, set2.stink_scale FROM set1 JOIN set2 ON set1.animal = set2.animal;
We will get the set:
+-------+--------+---------+-------------+
| color | animal | animal2 | stink_scale |
+-------+--------+---------+-------------+
| brown | dog | dog | 5 |
| white | dog | dog | 5 |
| black | dog | dog | 5 |
| green | parrot | parrot | 4 |
| green | turtle | turtle | 2 |
| brown | turtle | turtle | 2 |
+-------+--------+---------+-------------+
And we use that to combine our IN conditions:
SELECT *
FROM table1
WHERE (color, animal, animal2, stink_scale) IN (SELECT set1.color, set1.animal, set2.animal as animal2, set2.stink_scale FROM set1 JOIN set2 ON set1.animal = set2.animal)
We only get 2 records back since there is no result in that subquery where brown | dog | parrot | 4 will exist.
So, in the end unless there is a reason to change the conditions, thus changing the definition of the result set, you probably best off leaving it alone. It really changes the logic.
I have been trying to figure out why this LIKE statement won't read properly.
CREATE VIEW sole_python_author(author_first_name, author_last_name,book_title)
AS SELECT
authors.first_name,authors.last_name, books.title
FROM authors, books
WHERE books.author_id = authors.author_id AND books.title LIKE '%python%';
If i remove 'python' the sample output is this:
author_first_name | author_last_name | book_title
-------------------+------------------+-----------------------------
Stephen | King | The Shining
Frank | Herbert | Dune
Arthur C. | Clarke | 2001: A Space Odyssey
Seuss | Theodor | The Cat in the Hat
Seuss | Theodor | Bartholomew and the Oobleck
Paulette | Bourgeois | Franklin in the Dark
Margaret Wise | Brown | Goodnight Moon
Louisa May | Alcott | Little Women
Margery Williams | Bianco | The Velveteen Rabbit
Burne | Hogarth | Dynamic Anatomy
Edgar Allen | Poe | The Tell-Tale Heart
Mark | Lutz | Programming Python
Mark | Lutz | Learning Python
Tom | Christiansen | Perl Cookbook
John | Worsley | Practical PostgreSQL
However, when I add 'python' to the code it returns 0 Rows. I believe the problem lies with the like statement but I'm unsure. I'm trying to get the output as follows:
Mark | Lutz | Programming Python
Mark | Lutz | Learning Python
or is my statement being performed correctly and the output should be 0 Rows?
LIKE keyword match String in a case sensitive way.
I think you want to use ILIKE which is similar to LIKE but is not case sensitive.
LIKE keyword is Case sensitive.
books.title LIKE '%Python%'
Or
LOWER(books.title) LIKE '%python%'
Or
books.title ILIKE '%python%'
My specific use case is that I want to sort a list of users by name; first name, last name. The user has a preferred name and a legal name. I want to order by the preferred name if it is present, but the legal name as fall back.
For example, given the follow table:
id | first_name | last_name | preferred_first_name | preferred_last_name
----+------------+-----------+----------------------+---------------------
9 | Ryan | Bently | Alan |
10 | Ryan | Do | Billy | Baxter
11 | Olga | Clancierz | |
12 | Anurag | Plaxty | | Henderson
13 | Sander | Cliff | Billy |
I want to sort like this:
Alan Bently
Anurag Henderson
Billy Baxter
Billy Cliff
Olga Clancierz
Normally, with just one name set of name fields I would just do this:
SELECT * from users ORDER BY users.first_name, users.last_name
What is the best way to order by preferred name fields when present, but fall back to other name fields when they are not present?
Try
ORDER BY COALESCE(users.preferred_first_name,users.first_name), users.last_name
I'm facing problem when trying to extract row that based on condition from another row.
Sample table:
GroupID | Name | Salary | Car
--------------------------------------------------------------------------------
9009 | Isaac | 10,000 | Honda
9009 | Ricky | | Nissan
9080 | Patrick | 20,000 | Ferrari
9080 | Susan | 30,000 | Nissan
Questions:
How should I query if I want to extract data like this:
GroupID | Name | Salary | Car
--------------------------------------------------------------------------------
9009 | Isaac | 10,000 | Honda
9080 | Patrick | 20,000 | Ferrari
based on condition car = Nissan?
Try this:
SELECT GroupID, Name, Salary, Car
FROM tableName
WHERE GroupID IN (SELECT GroupID
FROM tableName
WHERE Car = 'Nissan') -- << Your input
AND car <> 'Nissan'
Read more about subqueries here.
SELECT * FROM yourTable where Car <> 'Nissan';
Would seem to do what you asked for.
You need to be more explicit about what you are trying to achieve here.
I guess this query is a little basic and I should know more about SQL but haven't done much with joins yet which I guess is the solution here.
What I have is a table of people and a table of job roles they hold. A person can have multiple jobs and I wish to have one set of results with a row per person containing their details and their job roles.
Two example tables (people and job_roles) are below so you can understand the question easier.
People
id | name | email_address | phone_number
1 | paul | paul#example.com | 123456
2 | bob | bob#example.com | 567891
3 | bart | bart#example.com | 987561
job_roles
id | person_id | job_title | department
1 | 1 | secretary | hr
2 | 1 | assistant | media
3 | 2 | manager | IT
4 | 3 | finance clerk | finance
4 | 3 | manager | IT
so that I can output each person and their roles like such
Name: paul
Email Address: paul#example.com
Phone: 123456
Job Roles:
Secretary for HR department
Assistant for media department
_______
Name: bob
Email address: bob#example.com
Phone: 567891
Job roles:
Manager for IT department
So how would I get each persons information (from the people table) along with their job details (from the job_roles table) to output like the example above. I guess it would be some kind of way of merging their jobs and their relevant departments into a jobs column that can be split up for output, but maybe there is a better way and what would the sql look like?
Thanks
Paul
PS it would be a mySQL database if that makes any difference
It looks like a straight-forward join:
SELECT p.*, j.*
FROM People AS p INNER JOIN Roles AS r ON p.id = r.person_id
ORDER BY p.name;
The remainder of the work is formatting; that's best done by a report package.
Thanks for the quick response, that seems a good start but you get multiple rows per person like (you have to imagine this is a table as you don't seem to be able to format in comments):
id | Name | email_address | phone_number | job_role | department
1 | paul | paul#example.com | 123456 | secretary | HR
1 | paul | paul#example.com | 123456 | assistant | media
2 | bob | bob#example.com | 567891 | manager | IT
I would like one row per person ideally with all their job roles in it if that's possible?
It depends on your DBMS, but most available ones do not support RVAs - relation-valued attributes. What you'd like is to have the job role and department part of the result like a table associated with the user:
+----+------+------------------+--------------+------------------------+
| id | Name | email_address | phone_number | dept_role |
+----+------+------------------+--------------+------------------------+
| | | | | +--------------------+ |
| | | | | | job_role | dept | |
| 1 | paul | paul#example.com | 123456 | | secretary | HR | |
| | | | | | assistant | media | |
| | | | | +--------------------+ |
+----+------+------------------+--------------+------------------------+
| | | | | +--------------------+ |
| | | | | | job_role | dept | |
| 2 | bob | bob#example.com | 567891 | | manager | IT | |
| | | | | +--------------------+ |
+----+------+------------------+--------------+------------------------+
This accurately represents the information you want, but is not usually an option.
So, what happens next depends on your report generation tool. Using the one I'm most familiar with, (Informix ACE, part of Informix SQL, available from IBM for use with the Informix DBMSs), you would simply ensure that the data is sorted and then print the name, email address and phone number in the 'BEFORE GROUP OF id' section of the report, and in the 'ON EVERY ROW' section you would process (print) just the role and department information.
It is often a good idea to separate the report formatting from the data retrieval operations; this is an example of where it is necessary unless your DBMS has unusual features to help with the formatting of selected data.
Oh dear that sounds very complicated and not something I could run easily on a mySQL database in a PHP page?
The RVA stuff - you're right, that is not for MySQL and PHP.
On the other hand, there are millions of reports (meaning results from queries that are formatted for presentation to a user) that do roughly this. The technical term for them is 'Control-Break Report', but the basic idea is not hard.
You keep a record of the 'id' number you last processed - you can initialize that to -1 or 0.
When the current record has a different id number from the previous number, then you have a new user and you need to start a new set of output lines for the new user and print the name, email address and phone number (and change the last processed id number). When the current record has the same id number, then all you do is process the job role and department information (not the name, email address and phone number). The 'break' occurs when the id number changes. With a single level of control-break, it is not hard; if you have 4 or 5 levels, you have to do more work, and that's why there are reporting packages to handle it.
So, it is not hard - it just requires a little care.
RE:
I was hoping SQL could do something
clever and join the rows together
nicely so I had essentially a jobs
column with that persons jobs in it.
You can get fairly close with
SELECT p.id, p.name, p.email_address, p.phone_number,
group_concat(concat(job_title, ' for ', department, ' department') SEPARATOR '\n') AS JobRoles
FROM People AS p
INNER JOIN job_roles AS r ON p.id = r.person_id
GROUP BY p.id, p.name, p.email_address, p.phone_number
ORDER BY p.name;
Doing it the way you're wanting would mean the result set arrays could have infinite columns, which would be very messy. for example, you could left join the jobs table 10 times and get job1, job2, .. job10.
I would do a single join, then use PHP to check if the name ID is the same from 1 row to the next.
One way might be to left outer join the tables and then load them up into an array using
$people_array =array();
while($row1=mysql_fetch_assoc($extract1)){
$people_array[] = $row1;
}
and then loop through using
for ($x=0;$x<=sizeof($people_array;)
{
echo $people_array[$x][id];
echo $people_array[$x][name];
for($y=0;$y<=$number_of_roles;$y++)
{
echo $people_array[$x][email_address];
echo $people_array[$x][phone_number];
$x++;
}
}
You might have to play with the query a bit and the loops but it should do generally what you want.For it to work as above every person would have to have the same number of roles, but you may be able to fill in the blanks in your table