I am working with a table that currently uses multiple CASE expressions to define the behavior of one of the columns, i.e.:
SELECT
Employee
,Company
,Department
,Area
,Flag = CASE
WHEN Company = 'Amazon' and Department in ('IT', 'HR')
THEN 0
WHEN Department = 'Legal'
THEN 1
WHEN Area = 'Cloud'
THEN 1
ELSE 0
END
FROM Table1
Which would result in something like the following dummy data:
Employee
Company
Department
Area
Flag
Cindy
Amazon
IT
Support
0
Jack
Amazon
HR
Support
0
Bob
Microsoft
Legal
Contracts
1
Joe
Amazon
Legal
Research
1
Lauren
Google
IT
Cloud
1
Jane
Apple
UX
Research
0
I am trying to simplify the Flag expression by using an auxiliary Mappings table that has the following structure, in order to get the value for the Flag column:
Company
Department
Area
Flag
Amazon
IT
NULL
0
Amazon
HR
NULL
0
NULL
Legal
NULL
1
NULL
NULL
Cloud
1
The NULL values mean the column could take any value. Is it possible to achieve this without falling into multiple CASE statements?
Related
I am trying to count how many makes of car a person owns. Car makes are only defined by a prefix in my Links table.
Table 1 (Person)
UniqueID Name
PER0001 Adrian
PER0002 Michael
Per0003 James
Table 2 (Links)
UniqueID LinkEnd1_ID LinkEnd2_ID
LIN0001 PER0001 FER02332
LIN0002 PER0001 FER02112
LIN0003 PER0001 POR12122
LIN0004 PER0002 FER12321
LIN0005 PER0003 MAS12382
LIN0006 PER0003 FER22982
LIN0006 PER0003 MAS12232
Output (option 1)
Name Car_Make Count
Adrian FER 2
Adrian POR 1
Michael FER 1
James MAS 2
James FER 1
Output (option 2 - preferred)
Name FER POR MAS
Adrian 1 2
Michael 1
James 1 2
The reason I am using a link table to count the number of car makes is because every car make has a different table I would need to join in.
I've tried
select count left(LinkEnd2_ID,3) which doesnt work, i've also tried group by which I cant seem to crack.
I guess what I want to be able to do is
select
count(left(LinkEnd2_ID,3)='FER'
,count(left(LinkEnd2_ID,3)='POR'
,count(left(LinkEnd2_ID,3)='MAS'
but thats a query in a select and I decipher how to code that properly.
Heres where I am starting from (or the base I keep going back to start afresh)-
SELECT
Person.Unique_ID
,Person.Name
,left(Link.LinkEnd2_ID,3) as Car_Make
FROM
Person
LEFT JOIN
Links as Link
on Person.Unique_ID = Link.LinkEnd1_ID
Any help you can offer would be appreciated.
Nearly there, you just need to add a group by, and change all the columns to aggregate functions.
Your option 1:
SELECT
max(Person.Name) as Person_Name
,left(Link.LinkEnd2_ID,3) as Car_Make
,count(*) as No_of_Car
FROM
Person
LEFT JOIN
Links as Link
on Person.Unique_ID = Link.LinkEnd1_ID
GROUP BY
Person.Unique_ID
For your option 2, you need to wrap your aggregate functions around case statements
you have to hardcode the 3 different car make, so if you have unknown number of them, it wouldn't work.
SELECT
max(Person.Name) as Person_Name
,sum(case when left(Link.LinkEnd2_ID,3) ='FER' then 1 else 0 end) as FER
,sum(case when left(Link.LinkEnd2_ID,3) ='POR' then 1 else 0 end) as POR
,sum(case when left(Link.LinkEnd2_ID,3) ='MAS' then 1 else 0 end) as MAS
FROM
Person
LEFT JOIN
Links as Link
on Person.Unique_ID = Link.LinkEnd1_ID
GROUP BY
Person.Unique_ID
I have a table ClientContacts, which holds basic information about a pairing of clients. Some of the details held in this table include P1Title, P2Title, P1FirstName, P2FirstName. For each row in this table there may be details of one or two clients, with a CustomerId that represents the pairing. Within this table is also ContactId, which is used to link to the table described below.
In a second table ContactDetails which contains rows that hold a specific contact detail that is associated with a client. Each client may have a number of rows in this table, each row holding a different detail such as HomeNumber, MobileNumber and Email. This table also contains a Type field which represents the type of contact detail held in the row. 1 = Home number, 2 = Mobile number and 3 = email. The Note field is also included, which may hold either Mr or Mrs denoting whether the mobile number held belongs to Person1 or Person2 in the client pairing.
Here is a visual structure of the tables.
ClientContacts
CustomerId ContactId Person1Title Person1FirstName Person1LastName Person2Title Person2FirstName Person2LastName
1 100 Mr Bob BobLastname Mrs Bobette BobetteLastname
2 101 Mr John JohnLastname Mrs Johnette JohnetteLastname
ContactDetails
ContactId Detail Type Note
100 012345 1
100 077777 2 P1
100 012333 1
100 088888 2 P2
101 099999 1
101 012211 1
101 066666 2
101 email#email.com 3
I want to construct a query that allows me to pull back the information of both of the clients, as well as figure out whether any of the mobile numbers stored in the ContactDetails table belongs to either of the two clients, if it does, I need to be able to tell which belongs to Person1 or Person2 in the pairing.
In addition, if the note field is null for a particular mobile number (type = 2), the first mobile number should be used for Person1 and the second should be used for Person2.
Below is my desired output:
Output
CustomerId Person1Firstname
Person1Lastname Person2Firstname Person2Lastname Home Person1Mobile Person2Mobile Person2Email
1 Bob BobLastname Bobette BobetteLastname 012211 077777 088888 null
I have a partially working query that manages to extract the mobile numbers and relates them to P1 or P2, however this only works if the Note field is not null.
select
cc.CustomerId,
cc.Person1Forename,
cc.Person1Surname,
cc.Person2Forename,
cc.Person2Surname,
max(case when cd.Type = 3 then cd.Detail end) as 'Home',
max(case when cd.Type = 4 and cd.Note = cc.P1Title then cd.Detail end) as 'Person1Mobile',
max(case when cd.Type = 4 and cd.Note = cc.P2Title then cd.Detail end) as 'Person2Mobile',
max(case when cd.Type = 5 then cd.Detail end) as 'Email'
from ClientContacts cc join
ContactDetails
cd on cc.ContactId = cd.ContactId
I'm unsure how to proceed from here. Any help would be appreciated.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a table in which I have loaded records from 4 different sources. There is no common factor between the records from each source except for FName, LName, Addr1, Addr2, City, State and Zip. Each record is assigned a FileID by me based upon which source file they were loaded from. I need to construct a query in which I can identify which person/household was found to be in all 4 files, 3 files, 2 files, etc. I only need to maintain one record for each duplicate person/household.
The other tricky part is that I have email address on 2 of the 4 files and also an Emailable field field that is coming in on the other two files. This is a factor which I need to consider also when maintaining the single selected record.
For example, one group will be indicated by: “individuals who are in all of the following lists: DMA , Vehicle Ownership and Lifestyle (Wealth Engine) lists. These individuals must have an email address.” But then another group needs to be identified as “individuals who are in all of the following lists: DMA , Vehicle Ownership and Lifestyle (Wealth Engine) lists. These individuals DO NOT have an email address”
Example Data:
ID FirstName LastName FullName Address1 Address2 City State Zip Zip4 EmailAddress FILE EMAILABLE
06925901SNDCR44110G6520 S Nylah Watson NULL 1234 Main NULL Anytown ST 10000 2000 NULL DMA Y
1641189779 Nylah Watson NULL 1234 Main Anytown ST 10000 2000 nylahwatson#gmail.com LST
06925901SNDCR44110G6520 S Nylah Watson NULL 1234 Main NULL Anytown ST 10000 2000 NULL VEH Y
374977111 Nylah Watson NULL 1234 Main NULL Anytown ST 10000 2000 nylahwatson#gmail.com V12 NULL
48770181SBRNT 1345M6352 S Watson Nylah NULL 4321 Main NULL HOUSTON TX 20000 3000 NULL DMA N
48770181SBRNT 1345M6352 S Watson Nylah NULL 4321 Main NULL HOUSTON TX 20000 3000 NULL VEH N
1933990731 Watson Nylah NULL 4321 Main Houston TX 20000 3000 LST
Depending on how many/how flexible the groups you need are, you may want to do something like this:
Select Name, Address... -- Fields you want to group on (consider to identify the same person)
, max(case when File = 'DMA' then 1 else 0 end) as HasDMAFile
, max(case when File = 'Veh' then 1 else 0 end) as HasVEHFile --repeat for your other file types
, max(case when emailaddress is not null then 1 else 0 end) as HasEmail
From MyTable
Group by Name, Address...--same list of fields as you use at the beginning of your select
Then use that result set to create your combination groups, for example:
; with CTE as (Query from Above)
Select *
, case when HasDMAFile = 1
and HasVEHFile = 1
and HasLSTFile = 1
and HasEmail = 0
then 'Group 1'
when HasDMAFile = 1
and HasVEHFile = 1
and HasLSTFile = 1
and HasEmail = 1
then 'Group 2' --etc for more groups here; make sure your groups are either mutually exclusive or in a logical order, since the case statement is evaluated in the order it's written
end as Grp
from CTE
SELECT
FName, LName, Addr1, Addr2, City, State, Zip,count(distinct File)
FROM <TABLE>
GROUP BY FName, LName, Addr1, Addr2, City, State, Zip
Having count(distinct File)=4
The emails could be coalesced, but you need to figure out an order of preference.
I have a query for a Placement Application Tracking System which shows the number of students placed and unplaced per programme of study. I'm struggling to create an APEX Stacked Bar Chart out of it, even though the query returns the desired results.
Query:
SELECT programme_name,
SUM(CASE WHEN (cv_approval_date IS NOT NULL AND application_status_id <> 7) OR
application_status_id IS NULL
THEN 1 ELSE 0 END) as Unplaced,
SUM(CASE WHEN (cv_approval_date IS NOT NULL AND application_status_id <> 7) OR
application_status_id IS NULL
THEN 0 ELSE 1 END) as Placed
FROM programme LEFT JOIN
student USING (programme_id) LEFT JOIN
application USING (student_id)
GROUP BY programme_name;
Output:
PROGRAMME_NAME | PLACED | UNPLACED
BSc (Hons) Computer Science | 2 | 2
BSc (Hons) Computing and Games Development | 1 | 0
BSc (Hons) Web Applications Development | 0 | 1
BSc (Hons) Marine Biology and Coastal Ecology | 1 | 0
The graph is supposed to look similar to this - the x axis being Programme, y axis being number of students placed, and unplaced:
http://ruepprich.files.wordpress.com/2011/03/stacked_bar.png?w=550&h=386
How might I go about doing this? Any help would be greatly appreciated!
When creating a chart in Apex you can click on "Chart Query Example" for some sample queries that will work with that chart type.
In the case of a stacked bar chart, the following example is given:
SELECT NULL LINK,
ENAME LABEL,
SAL "Salary",
COMM "Commission"
FROM EMP
ORDER BY ENAME
In your case I think you'll want your query to present the following format:
SELECT NULL LINK,
programme_name AS LABEL,
SUM(...) AS "Unplaced",
SUM(...) AS "Placed"
FROM ...
I was wondering, what is the most efficient way of combining results into a single result.
I want to turn
Num Ani Country
---- ----- -------
22 cows Canada
20 pigs Canada
40 cows USA
34 pigs USA
into:
cows pigs Country
----- ----- -------
22 20 Canada
40 34 USA
I want to know if it would be better to use SQL only or if I should feed the whole query result set to the user. Once given to the user, I could use JavaScript to parse it into the desired format.
Also, I do not know exactly how I would change this into the right format for a SQL query. The only way I can think of approaching this SQL statement is very roundabout with dynamically creating a temporary table.
The operation you're after is called "pivoting" - the PIVOT info page has a little more detail:
SELECT MAX(CASE WHEN t.ani = 'cows' THEN t.num ELSE NULL END) AS cows,
MAX(CASE WHEN t.ani = 'pigs' THEN t.num ELSE NULL END) AS pigs,
t.country
FROM YOUR_TABLE t
GROUP BY t.country
ORDER BY t.country
There should be an efficient way using a 2-D array on the client-side (php) to achieve the pivoting. To address Ken Downs' concerns about byte pushing, a ragged raw pivot data consumes less bytes than a fully materialized 2-D pivot table, the simple case is
cows | pigs | sheep | goats | country
1 null null null Canada
null 2 null null USA
null null 3 null Egypt
null null null 4 England
which is only 4 rows of raw data (each being 3 columns).
Doing it in the front end also solves the issue of dynamic-pivoting. If your number of pivot columns is unknown, then you would require a MySQL procedure to build up a dynamic sql statement of the pattern "MAX(CASE....)" for each column.
There are advantages to doing this on the client side
can be done (at least considered as an alternative)
can be rendered earlier, if the savings in network traffic is significant despite requiring either (1) php pivottable construction or (2) client side javascript
does not require a MySQL procedure for dynamic pivoting