Sql database query design for establishing priority levels - sql

I am facing issues trying to write a query.
My tables are laid out as follows:
tblTicketIssues
TicketID | RequesterID
tblPersonnelProfile
PersonnelID | FirstName | LastName
tblTicketAttribute
TicketID | Attribute | AttributeValue
I have to display the following fields:
TicketID,
RequesterFullName,
UrgentPriorityID,
MediumPriorityID,
LowPrioritytID
This is the part that is challenging:
If tblTicketAttribute.Attribute=
"Urgent" then the value from
tblTicketAttribute.AttributeValue is
displayed in UrgentPriority column
If tblTicketAttribute.Attribute=
"Medium" then the value from
tblTicketAttribute.AttributeValue is
displayed in MediumPriority column
If tblTicketAttribute.Attribute= "Low"
then the value from
tblTicketAttribute.AttributeValue is
displayed in LowPriority column
The values in tblTicketAttribute.Attribute include "Urgent", "Medium", "Low", "Over30", "Over60", "Over90", "Closed"
How can I do this?

Check out the CASE statement.
select
ticketID
,Lastname +', '+firstname
,CASE attribute
WHEN 'Urgent' THEN attributeValue
ELSE ''
END as UrgentPriorityID
,CASE attribute
WHEN 'Medium' THEN attributeValue
ELSE ''
END as MediumPriorityID
,CASE attribute
WHEN 'Low' THEN attributeValue
ELSE ''
END as LowPrioritytID
from
...

I've made the assumption that RequestorID is the foreign key for the PersonnelID primary key in tblPersonnelProfile. This should do it for SQL Server
SELECT
issues.TicketID,
personnel.FirstName + ' ' + personnel.LastName AS RequesterFullName,
CASE WHEN attribute.Attribute = 'Urgent' THEN attribute.AttributeValue ELSE NULL END AS UrgentPriorityID,
CASE WHEN attribute.Attribute = 'Medium' THEN attribute.AttributeValue ELSE NULL END AS MediumPriorityID,
CASE WHEN attribute.Attribute = 'Low' THEN attribute.AttributeValue ELSE NULL END AS LowPrioritytID
FROM
tblTicketIssues issues
INNER JOIN
tblPersonnelProfile personnel
ON
issues.RequestorID = personnel.PersonnelID
INNER JOIN
tblTicketAttribute attribute
ON
issues.TicketID = attribute.TicketID

Using the CASE statement as jms or Russ have done is probably the much better way to go, but you could also use sub-selects to solve the problem:
SELECT ti.TicketID,
pp.FirstName || ' ' || pp.LastName AS RequesterFullName,
(SELECT ta.AttributeValue FROM tblTicketAttribute AS ta WHERE ta.Attribute = 'Urgent' AND ta.TicketID = ti.TicketID) AS UrgentPriorityID,
(SELECT ta.AttributeValue FROM tblTicketAttribute AS ta WHERE ta.Attribute = 'Medium' AND ta.TicketID = ti.TicketID) AS MediumPriorityID,
(SELECT ta.AttributeValue FROM tblTicketAttribute AS ta WHERE ta.Attribute = 'Low' AND ta.TicketID = ti.TicketID) AS LowPriorityID
FROM tblTicketIssues AS ti
INNER JOIN tblPersonnelProfile AS pp ON ti.RequestorID = pp.PersonnelID;
I suspect the CASE would be much faster, but you never know until you measure, and sometimes the sub-select approach is your only option. You'll automatically get NULLs in the sub-select columns if the WHERE predicate is false.
Also, you get to see a whole 'nuther way to format SQL queries, as well as the more Oracle-ish concatenation operator.
I should also mention that the sub-select won't work if the TicketID column in tblTicketAttribute is not unique, but the other options may give wonky results too, if that's the case.

Related

SQL spread column GROUP into a single row without multiple JOIN [duplicate]

If I have a MySQL table looking something like this:
company_name action pagecount
-------------------------------
Company A PRINT 3
Company A PRINT 2
Company A PRINT 3
Company B EMAIL
Company B PRINT 2
Company B PRINT 2
Company B PRINT 1
Company A PRINT 3
Is it possible to run a MySQL query to get output like this:
company_name EMAIL PRINT 1 pages PRINT 2 pages PRINT 3 pages
-------------------------------------------------------------
CompanyA 0 0 1 3
CompanyB 1 1 2 0
The idea is that pagecount can vary so the output column amount should reflect that, one column for each action/pagecount pair and then number of hits per company_name. I'm not sure if this is called a pivot table but someone suggested that?
This basically is a pivot table.
A nice tutorial on how to achieve this can be found here: http://www.artfulsoftware.com/infotree/qrytip.php?id=78
I advise reading this post and adapt this solution to your needs.
Update
After the link above is currently not available any longer I feel obliged to provide some additional information for all of you searching for mysql pivot answers in here. It really had a vast amount of information, and I won't put everything from there in here (even more since I just don't want to copy their vast knowledge), but I'll give some advice on how to deal with pivot tables the sql way generally with the example from peku who asked the question in the first place.
Maybe the link comes back soon, I'll keep an eye out for it.
The spreadsheet way...
Many people just use a tool like MSExcel, OpenOffice or other spreadsheet-tools for this purpose. This is a valid solution, just copy the data over there and use the tools the GUI offer to solve this.
But... this wasn't the question, and it might even lead to some disadvantages, like how to get the data into the spreadsheet, problematic scaling and so on.
The SQL way...
Given his table looks something like this:
CREATE TABLE `test_pivot` (
`pid` bigint(20) NOT NULL AUTO_INCREMENT,
`company_name` varchar(32) DEFAULT NULL,
`action` varchar(16) DEFAULT NULL,
`pagecount` bigint(20) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=MyISAM;
Now look into his/her desired table:
company_name EMAIL PRINT 1 pages PRINT 2 pages PRINT 3 pages
-------------------------------------------------------------
CompanyA 0 0 1 3
CompanyB 1 1 2 0
The rows (EMAIL, PRINT x pages) resemble conditions. The main grouping is by company_name.
In order to set up the conditions this rather shouts for using the CASE-statement. In order to group by something, well, use ... GROUP BY.
The basic SQL providing this pivot can look something like this:
SELECT P.`company_name`,
COUNT(
CASE
WHEN P.`action`='EMAIL'
THEN 1
ELSE NULL
END
) AS 'EMAIL',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '1'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 1 pages',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '2'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 2 pages',
COUNT(
CASE
WHEN P.`action`='PRINT' AND P.`pagecount` = '3'
THEN P.`pagecount`
ELSE NULL
END
) AS 'PRINT 3 pages'
FROM test_pivot P
GROUP BY P.`company_name`;
This should provide the desired result very fast. The major downside for this approach, the more rows you want in your pivot table, the more conditions you need to define in your SQL statement.
This can be dealt with, too, therefore people tend to use prepared statements, routines, counters and such.
Some additional links about this topic:
http://anothermysqldba.blogspot.de/2013/06/pivot-tables-example-in-mysql.html
http://www.codeproject.com/Articles/363339/Cross-Tabulation-Pivot-Tables-with-MySQL
http://datacharmer.org/downloads/pivot_tables_mysql_5.pdf
https://codingsight.com/pivot-tables-in-mysql/
My solution is in T-SQL without any pivots:
SELECT
CompanyName,
SUM(CASE WHEN (action='EMAIL') THEN 1 ELSE 0 END) AS Email,
SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END) AS Print1Pages,
SUM(CASE WHEN (action='PRINT' AND pagecount=2) THEN 1 ELSE 0 END) AS Print2Pages,
SUM(CASE WHEN (action='PRINT' AND pagecount=3) THEN 1 ELSE 0 END) AS Print3Pages
FROM
Company
GROUP BY
CompanyName
For MySQL you can directly put conditions in SUM() function and it will be evaluated as Boolean 0 or 1 and thus you can have your count based on your criteria without using IF/CASE statements
SELECT
company_name,
SUM(action = 'EMAIL')AS Email,
SUM(action = 'PRINT' AND pagecount = 1)AS Print1Pages,
SUM(action = 'PRINT' AND pagecount = 2)AS Print2Pages,
SUM(action = 'PRINT' AND pagecount = 3)AS Print3Pages
FROM t
GROUP BY company_name
DEMO
For dynamic pivot, use GROUP_CONCAT with CONCAT.
The GROUP_CONCAT function concatenates strings from a group into one string with various options.
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(CASE WHEN action = "',
action,'" AND ',
(CASE WHEN pagecount IS NOT NULL
THEN CONCAT("pagecount = ",pagecount)
ELSE pagecount IS NULL END),
' THEN 1 ELSE 0 end) AS ',
action, IFNULL(pagecount,'')
)
)
INTO #sql
FROM
t;
SET #sql = CONCAT('SELECT company_name, ', #sql, '
FROM t
GROUP BY company_name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DEMO HERE
A stardard-SQL version using boolean logic:
SELECT company_name
, COUNT(action = 'EMAIL' OR NULL) AS "Email"
, COUNT(action = 'PRINT' AND pagecount = 1 OR NULL) AS "Print 1 pages"
, COUNT(action = 'PRINT' AND pagecount = 2 OR NULL) AS "Print 2 pages"
, COUNT(action = 'PRINT' AND pagecount = 3 OR NULL) AS "Print 3 pages"
FROM tbl
GROUP BY company_name;
db<>fiddle here
Old sqlfiddle
How?
TRUE OR NULL yields TRUE.
FALSE OR NULL yields NULL.
NULL OR NULL yields NULL.
And COUNT only counts non-null values. Voilá.
Correct answer is:
select table_record_id,
group_concat(if(value_name='note', value_text, NULL)) as note
,group_concat(if(value_name='hire_date', value_text, NULL)) as hire_date
,group_concat(if(value_name='termination_date', value_text, NULL)) as termination_date
,group_concat(if(value_name='department', value_text, NULL)) as department
,group_concat(if(value_name='reporting_to', value_text, NULL)) as reporting_to
,group_concat(if(value_name='shift_start_time', value_text, NULL)) as shift_start_time
,group_concat(if(value_name='shift_end_time', value_text, NULL)) as shift_end_time
from other_value
where table_name = 'employee'
and is_active = 'y'
and is_deleted = 'n'
GROUP BY table_record_id
There is a tool called MySQL Pivot table generator, it can help you create a web-based pivot table that you can later export to excel(if you like). it can work if your data is in a single table or in several tables.
All you need to do is to specify the data source of the columns (it supports dynamic columns), rows, the values in the body of the table, and table relationship (if there are any)
The home page of this tool is https://mysqlreports.com/mysql-reporting-tools/mysql-pivot-table/
select t3.name, sum(t3.prod_A) as Prod_A, sum(t3.prod_B) as Prod_B, sum(t3.prod_C) as Prod_C, sum(t3.prod_D) as Prod_D, sum(t3.prod_E) as Prod_E
from
(select t2.name as name,
case when t2.prodid = 1 then t2.counts
else 0 end prod_A,
case when t2.prodid = 2 then t2.counts
else 0 end prod_B,
case when t2.prodid = 3 then t2.counts
else 0 end prod_C,
case when t2.prodid = 4 then t2.counts
else 0 end prod_D,
case when t2.prodid = "5" then t2.counts
else 0 end prod_E
from
(SELECT partners.name as name, sales.products_id as prodid, count(products.name) as counts
FROM test.sales left outer join test.partners on sales.partners_id = partners.id
left outer join test.products on sales.products_id = products.id
where sales.partners_id = partners.id and sales.products_id = products.id group by partners.name, prodid) t2) t3
group by t3.name ;
One option would be combining use of CASE..WHEN statement is redundant within an aggregation for MySQL Database, and considering the needed query generation dynamically along with getting proper column title for the result set as in the following code block :
SET #sql = NULL;
SELECT GROUP_CONCAT(
CONCAT('SUM( `action` = ''', action, '''',pc0,' ) AS ',action,pc1)
)
INTO #sql
FROM
(
SELECT DISTINCT `action`,
IF(`pagecount` IS NULL,'',CONCAT('page',`pagecount`)) AS pc1,
IF(`pagecount` IS NULL,'',CONCAT(' AND `pagecount` = ', pagecount, '')) AS pc0
FROM `tab`
ORDER BY CONCAT(action,pc0)
) t;
SET #sql = CONCAT('SELECT company_name,',#sql,' FROM `tab` GROUP BY company_name');
SELECT #sql;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Demo
SELECT company_name, SUM(CASE WHEN ACTION = 'Email' THEN 1 ELSE 0 END) AS "Email",
SUM(CASE WHEN ACTION = 'Print' AND pagecount = 1 THEN 1 ELSE 0 END) AS "print 1 PAGE",
SUM(CASE WHEN ACTION = 'Print' AND pagecount = 2 THEN 1 ELSE 0 END) AS "print 2 PAGE",
SUM(CASE WHEN ACTION = 'Print' AND pagecount = 3 THEN 1 ELSE 0 END) AS "print 2 PAGE"
FROM test1 GROUP BY company_name;

Query timeout increased but script fails to execute

When i execute this script on my remote database it gives me query timeout error. I've increased the timeout on my database but still have this error. I've been told if i'm able to optimized the script to make it simple it might work.
SELECT TOP 8 MIN( CASE WHEN pic_alb_love.pic=users_pics.pic
AND pic_alb_love.email = 'try#mail.com' THEN 'User' ELSE 'Guest' END)AS answer_one,
MIN ( CASE WHEN favorites.pic=users_pics.pic AND favorites.email = 'try#mail.com' THEN 'good' ELSE 'Bad'
END)AS answer2,
(CASE WHEN RTRIM (users_pics.upload_type) = 'wow' THEN 'loaded' ELSE
CASE WHEN RTRIM (users_pics.upload_type)= 'hey' THEN 'added' ELSE
CASE WHEN RTRIM (users_pics.upload_type) = 'check' THEN 'Changed' END END END)as up_ans,
(CASE WHEN RTRIM (users_pics.upload_type) = 'sample1' THEN 'new' ELSE
CASE WHEN RTRIM (users_pics.upload_type) = 'sample2' THEN 'existing' ELSE
CASE WHEN RTRIM (users_pics.upload_type) = 'sample3' THEN 'Profile Picture' END END END) as exs,
COUNT(DISTINCT users_pics.pic) as total,RTRIM (users_pics.wardrobe) as wardrobe,
fname,users_pics.wardrobe,
MIN (make)as make,MIN (htags)as htags, RTRIM (profile.profile_id) as profile_id,
users_pics.email,profile.profile_pix, RTRIM (profile.gender) as gender,
users_pics.time_group,profile.fpage,up_user_id, MIN (u_pic_id) as u_pic_id, MIN (users_pics.pic) as pic
FROM users_pics
LEFT join profile on users_pics.email = profile.email
LEFT join favorites on users_pics.pic = favorites.pic
LEFT JOIN pic_alb_love on users_pics.pic = pic_alb_love.pic
left join friends on users_pics.email = friends.resp_email
WHERE req_email = 'try#mail.com' and pic_enable='enable' or pic_view='Public'
GROUP BY users_pics.upload_type,profile.fname,profile.profile_id,users_pics.wardrobe,
users_pics.email, profile.gender,users_pics.time_group,profile.profile_pix, profile.fpage,up_user_id
ORDER BY MIN (users_pics.u_pic_id) DESC
Increasing timeout can help, but you should also check if your query isn't blocked by others operations like INSERT/UPDATE or open transaction.
The easiest way is to install and use sp_whoisactive procedure.
Second you don't need to nest CASE like you did:
(CASE WHEN RTRIM (users_pics.upload_type) = 'wow' THEN 'loaded' ELSE
CASE WHEN RTRIM (users_pics.upload_type)= 'hey' THEN 'added' ELSE
CASE WHEN RTRIM (users_pics.upload_type) = 'check' THEN 'Changed' END END END)as up_ans,
to
CASE RTRIM (user_pics.upload_type)
WHEN 'wow' THEN 'loaded'
WHEN 'hey' THEN 'added'
WHEN 'check' THEN 'changed'
ELSE NULL /* or your value like 'unknown' */
END AS up_ans
Next thing: you RTRIM almost on every string value, you should sanitize your input during inserting, unless you need spaces/tabs/newline and so on.
This way your query won't need RTRIM and can utilize index if exists any.
/* New values */
INSERT INTO table_name(...) VALUES (LTRIM(RTRIM(value...)))
/* Existing ones */
UPDATE table_name
SET col = LTRIM(RTRIM(col))
SQL Parser will understand wall of text, human will need time to do it.
I know we can argue about code style but remember you write code for people. Good readable code allow you to spot errors earlier and it is a hell easier to maintain in the future for you and your successors:
1) One selected value one line
2) The same order in SELECT and GROUP BY
3) Aggregated columns at end
4) You can use aliases no need for fully qualified names
5) No ambiguous column names, always specify from which table
6) SQL syntax UPPER CASE
7) Allign your code
Your query in more human readable from:
SELECT TOP 8
[up_user_id] /* Always add from which table even if it is unique column name, because in future you may get ambigous column */
,[fname]
,[profile_id] = RTRIM(profile.profile_id)
,[up_ans] = CASE RTRIM(users_pics.upload_type)
WHEN 'wow' THEN 'loaded'
WHEN 'hey' THEN 'added'
WHEN 'check' THEN 'changed'
ELSE NULL
END
,[exs] = CASE RTRIM(users_pics.upload_type)
WHEN 'sample1' THEN 'new'
WHEN 'sample2' THEN 'existing'
WHEN 'sample3' THEN 'Profile Picture'
ELSE NULL
END
,[wardrobe] = RTRIM(users_pics.wardrobe)
,users_pics.email
,[gender] = RTRIM(profile.gender)
,users_pics.time_group
,profile.profile_pix
,profile.fpage
,[answer_one] = MIN(CASE
WHEN pic_alb_love.pic=users_pics.pic THEN 'User'
ELSE 'Guest'
END)
,[answer2] = MIN(CASE
WHEN favorites.pic = users_pics.pic AND favorites.email = 'try#mail.com' WHEN 'good'
ELSE 'Bad'
END)
,[total] = COUNT(DISTINCT users_pics.pic)
,[make] = MIN(make)
,[htags] = MIN(htags)
,[u_pic_id] = MIN(u_pic_id)
,[pic] = MIN(users_pics.pic)
FROM users_pics /* you can use alias like AS up */
LEFT JOIN profile
ON users_pics.email = profile.email
LEFT JOIN favorites
ON users_pics.pic = favorites.pic
LEFT JOIN pic_alb_love
ON users_pics.pic = pic_alb_love.pic
LEFT JOIN friends
ON users_pics.email = friends.resp_email
WHERE
req_email = 'try#mail.com'
AND pic_enable = 'enable'
OR pic_view = 'Public'
GROUP BY
up_user_id
,profile.fname
,profile.profile_id
,users_pics.upload_type
,users_pics.wardrobe
,users_pics.email
,profile.gender
,users_pics.time_group
,profile.profile_pix
,profile.fpage
ORDER BY MIN(users_pics.u_pic_id) DESC
After you check that your query is not blocked during selecting data you can think about:
checking indexes on your tables
add WHERE condition to fetch smaller set, maybe you can use some update_date > current_date - 2 weeks
think to optimize query because now it does grouping and ordering which needs time to complete.
your WHERE condition, are you sure it shouldn't be:
.
WHERE (req_email = 'try#mail.com'
AND pic_enable = 'enable')
OR pic_view = 'Public'

Optimise the update query which exceeds 30 secs of execution time

I have written a procedure which adds the data to database in case is not present (duplicate). If the data is duplicated then the empty fields in the database will be updated.
eg: first time the entry is
companyname email_id contact_name designation mobile fax country
1 abc xyz#abc.com xyz pqr
Now if the entry comes second time with some extra data then
2 abc xyz#abc.com xyz pqr 0987765 087722 South Africa
Now the existing data will be updated only for empty field i.e. only mobile fax and country will be updated in the existing data.
Now my query for updating is as follows:
UPDATE dbo.companyinfo SET companyinfo.companyname=case when companyinfo.companyname='' or companyinfo.companyname=null then RESULT.companyname else companyinfo.companyname end ,
companyinfo.website= case when companyinfo.website='' OR companyinfo.website IS NULL then RESULT.website else companyinfo.website end ,
companyinfo.contactperson= case when companyinfo.contactperson='' OR companyinfo.contactperson IS NULL then RESULT.contactperson else companyinfo.contactperson end,companyinfo.country = case when companyinfo.country=1 OR companyinfo.country IS NULL then RESULT.country else companyinfo.country end,
companyinfo.telphone=case when companyinfo.telphone='' OR companyinfo.telphone IS NULL then RESULT.telphone else companyinfo.telphone end,companyinfo.mobile= case when companyinfo.mobile='' OR companyinfo.mobile IS NULL then RESULT.mobile else companyinfo.mobile end ,
companyinfo.fax= case when companyinfo.fax='' OR companyinfo.fax IS NULL then RESULT.fax else companyinfo.fax end, companyinfo.region= case when companyinfo.region=2 OR companyinfo.region IS NULL then RESULT.region else companyinfo.region end,companyinfo.urlorcatalog=RESULT.urlorcatalog,companyinfo.address= case when companyinfo.address='' OR companyinfo.address IS NULL then RESULT.address else companyinfo.address end,
companyinfo.lastupdatedby=RESULT.lastupdatedby
FROM
(
select TEMP1.companyname,TEMP1.website,TEMP1.contactperson,TEMP1.country, TEMP1.telphone , TEMP1.mobile, TEMP1.fax,TEMP1.region, TEMP1.urlorcatalog,TEMP1.address,TEMP1.lastupdatedby, TEMP1.DataID
from
(
SELECT tmp.companyname,tmp.website,tmp.contactperson,tmp.country,tmp.telphone,tmp.mobile,tmp.fax, tmp.region,tmp.urlorcatalog,tmp.address,tmp.lastupdatedby,Email.DataID,ROW_NUMBER() OVER (PARTITION BY tmp.email ORDER BY tmp.email ) AS 'RowNumber'
FROM #TempTable tmp
LEFT OUTER JOIN emailinfo Email ON tmp.email =Email.email
WHERE
tmp.email !=''
AND
EXISTS (SELECT emailinfo.email FROM dbo.emailinfo WHERE email=tmp.email)
)AS TEMP1
LEFT OUTER JOIN dbo.companyinfo COMPANY ON TEMP1.DataID =COMPANY.dataId
WHERE
TEMP1.RowNumber =1
) AS RESULT
WHERE companyinfo.dataId =RESULT.DataID
Sometimes i get an error saying "Unable to add Timeout expired. Timeout period elapsed prior to completion of the operation or the server is not responding" and through sql profiler i came to know the duration of the above query exceeds 30 secs.
The execution time of this query exceeds 30 seconds. How can i optimize the query so that the execution times becomes less then 30 seconds.
*Note the above query is the part of the procedure
Try using merge statement
MERGE INTO yourtable AS Target
USING (VALUES ('abc',
'xyz#abc.com',
'xyz',
'pqr',
0987765,
087722,
'South Africa')) AS Source (companyname, email_id, contact_name, designation, mobile, fax, country )
ON Target.companyname = Source.companyname
AND Target.email_id = Source.email_id
AND Target.contact_name = Source.contact_name
AND Target.designation = Source.designation
WHEN MATCHED THEN
UPDATE SET companyname = CASE WHEN target.companyname IS NULL OR target.companyname = '' THEN Source.companyname ELSE target.companyname END,
email_id = CASE WHEN target.email_id IS NULL OR target.email_id = '' THEN Source.email_id ELSE target.email_id END,
contact_name = CASE WHEN target.contact_name IS NULL OR target.contact_name = '' THEN Source.contact_name ELSE target.contact_name END,
designation = CASE WHEN target.designation IS NULL OR target.designation = '' THEN Source.designation ELSE target.designation END,
mobile = CASE WHEN target.mobile IS NULL OR target.mobile = '' THEN Source.designation ELSE target.mobile END,
fax = CASE WHEN target.fax IS NULL OR target.fax = '' THEN Source.fax ELSE target.fax END,
country = CASE WHEN target.country IS NULL OR target.country = '' THEN Source.country ELSE target.country END
WHEN NOT MATCHED BY TARGET THEN
INSERT (companyname,
email_id,
contact_name,
designation,
mobile,
fax,
country )
VALUES (companyname,
email_id,
contact_name,
designation,
mobile,
fax,
country );
Note : Modifiy the join ON condition based on your requirement
Well, there seems to be nothing inherently wrong with the query that would explain why it is taking so long. I would look at the query plan to see what it is doing.
I would also look into indenting (for readability) and improve the sub-query (as it seems overly complicated)

Sorting based on multiple conditions

I am doing a exercise
I'll fire a query on the DB and get some 500 results. Now i want to sort this list based on some conditions and present the sorted list in client side.
I am using Java/Java EE and MySQL server 5.5
Conditions are like this,
Example: Consider a table having listed with cars
So, i ll fire a query on the table and it will list some 500 cars. now i want to sort this list based on user criteria.
conditions are age of car, colour of car and facilities of cars. List should be sorted like this
First appears the list of cars which satisfies all three conditions ie., same age as mentioned by end user, same colour and with all facilities user selected.
Second appears any 2 conditions satisfying cars list and one condition not satifying.
Third appears any one condition satisfying cars list and not the other two.
And finally appears the list of cars of which no conditions are satisfied.
How can i achieve this. I have searched in google, asked in irc channels regarding this. Couldn't get any help.
I have tried using RANK function by defining the CASES and finally order by RANK. It works for me while the conditions fields (columns) are of same table. In my case the fields are from a parent table as well as its child tables which has many to one relationship with its parent. Like in this example, age and color of the cars are stored in parent table and facilities that cars has are stored in another table. I tried doing the same using inner join, but no luck.
I tried something like this:
Query:
select distinct t0.id,t0.name,t0.price,
CASE
WHEN
t1.age='2' AND t1.colour='Red' AND t2.facilities_id=9 THEN 1
WHEN
t1.age='2' AND t1.colour='Red' AND t2.facilities_id!=9 THEN 2
WHEN
t1.age='2' AND t1.colour!='Red' AND t2.facilities_id=9 THEN 3
WHEN
t1.age!='2' AND t1.colour='Red' AND t2.facilities_id=9 THEN 4
WHEN
t1.age!='2' AND t1.colour='Red' AND t2.facilities_id!=9 THEN 5
WHEN
t1.age='2' AND t1.colour!='Red' AND t2.facilities_id!=9 THEN 6
WHEN *
t1.age!='2' AND t1.colour!='Red' AND t2.facilities_id=9 THEN 7
ELSE 8
END as pre_status
from cars_listing t0
inner join
cars_listing_details t1
on t0.id=t1.mg_listing_id
inner join
cars_facilities_listing t2
on t1.cars_listing_id=t2.listing_id
where t0.type='new_cars'
order by pre_status
Thanks in advance for helping.
try ordering by something like...
order by
case when first_condition then 1 else 0 end
+ case when second_condition then 1 else 0 end
+ case when third_condition then 1 else 0 end DESC
select distinct
t0.id,
t0.name,
t0.price,
case when t1.age = '2' then 1 else 0 end as MatchedAge,
case when t1.colour='Red' then 1 else 0 end as MatchedColor,
case when t2.facilities_id = 9 THEN 1 else 0 end as MatchedFacility
from
cars_listing t0
inner join cars_listing_details t1
on t0.id = t1.mg_listing_id
inner join cars_facilities_listing t2
on t1.cars_listing_id = t2.listing_id
where
t0.type = 'new_cars'
order by
case when t1.age = '2' then 1 else 0 end
+ case when t1.colour='Red' then 1 else 0 end
+ case when t2.facilities_id = 9 THEN 1 else 0 end DESC
If one field is a higher priority -- such as a red car, you could even give that more weight than the other in the order by... So a Red car at Facility 5 would show before a Blue car at facility 9 just by changing the order by to something like
order by
case when t1.age = '2' then 1 else 0 end
+ case when t1.colour='Red' then 5 else 0 end <-- applyi higher Wgt to color match vs other criteria
+ case when t2.facilities_id = 9 THEN 1 else 0 end DESC
Well, I have done Dynamic sql where condition in my project. It might help you. I have created a stored procedure for SELECT query. (I have done it in SQL Server 2008 R2). Tell me if you need more help.
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[PROCEDURE_NAME]
#Id int = NULL,
#Requester varchar(20) = NULL,
#Suggester varchar(20) = NULL
AS
BEGIN
DECLARE #sql nvarchar(4000)
SELECT #sql='SELECT Id, Suggester, Requester from DATABASE_NAME.dbo.TABLE_NAME WHERE 1=1 '
If (#Id) IS NOT NULL
SELECT #sql=#sql + ' AND Id=(#Id) '
If (#Suggester) IS NOT NULL
SELECT #sql=#sql + ' AND Suggester like (#Suggester) '
If (#Requester) IS NOT NULL
SELECT #sql=#sql + ' AND Requester like (#Requester) '
EXEC sp_executesql #sql, N'#id int, #Requester varchar(20), #Suggester varchar(20)',
#Id, #Requester, #Suggester
END
GO
Here in this SP; Id,Requester,Suggester are field names.

In SQL (Tsql) what's a good way to check mutually exclusive options are correct

EDIT: damien the unbeliever, my apologies, trying to be terse I omitted saying that the design of the table is not under my control; this table is a "dump" of data we receive from another vendor, and I have to convert it from their format to ours. The reason I need a query is to find out if the data is consistent with assumptions in other parts of code. The solutions proposed looking for length or exact match of the concatenated strings are better than my pair of queries for the problem I described.
I have a working pair of queries for my problem, but I wondered if there's something a bit prettier. Exactly one of taxidflag1, taxidflag2, taxidflag3 should be filled in with * in each row. So I confirm they all have two blanks and one * like this. All fields are are non nullable.
select * from acct where 2 <>
(case when taxidFlag1 <> '' then 1 else 0 end) +
(case when taxidFlag2 <> '' then 1 else 0 end) +
(case when taxidFlag3 <> '' then 1 else 0 end)
select * from acct where 1 <>
(case when taxidFlag1 = '*' then 1 else 0 end) +
(case when taxidFlag2 = '*' then 1 else 0 end) +
(case when taxidFlag3 = '*' then 1 else 0 end)
You could do this:
select * from acct where taxidFlag1 + taxidFlag2 + taxidFlag3 = '*';
This condition is only true if two are empty ('') and one is a asterisk (*).
select *
from
acct a1
where
(select count(*) from acct unpivot (foo for taxidFlag in (taxidFlag1, taxidFlag2, taxidFlag3)) as unp where unp.row_id = a1.row_id and foo = '*') <> 1
;
where row_id is your primary key field.