SQL advanced compare of strings - sql

I am working on getting some very specific information out of a MSSQL database. All the information I need is available via this SQL command:
SELECT
receivedate,
swp.firmwarelevel AS 'Firmwarelevel',
pa.description AS 'Description'
FROM tbl_swapgroup_parts swp, tbl_parts pa, tbl_part_type pt, tbl_swapgroups sw, tbl_workorders wo
WHERE custom7 = 'somemodel'
AND swp.swapgroup_id IN (18,25)
AND sw.id = swp.swapgroup_id
AND pa.id = swp.part_id
AND pt.id = pa.parttype_id
AND wo.part_id = pa.id'
Now this returns a list which looks something like this, trimmed to just 4 entries for sanity...
+---------------------+---------------+--------------------------------------------------+
| receivedate | Firmwarelevel | Description |
+---------------------+---------------+--------------------------------------------------+
| 2013-08-29 12:10:28 | YN07 | Description 1... |
| 2013-08-29 12:10:28 | YN07 | Description 2... |
| 2014-01-13 13:12:55 | YN07 | Description 1... |
| 2014-01-13 13:12:55 | YN07 | Description 2... |
+---------------------+---------------+--------------------------------------------------+
So what I want is really only 1 entry for each Unique description string, and the unique entry has to be the one with the newest recievedate.
Is such an 'advanced' thing possible only in SQL or do I have to post-process with some other language like python?
If at all possible I`d like to do it in pure SQL...

Yes, you can do this in SQL. For example, with row_number():
SELECT * FROM (
SELECT
receivedate,
swp.firmwarelevel AS 'Firmwarelevel',
pa.description AS 'Description',
row_number() over (partition by Description order by receivedate desc) rn
FROM tbl_swapgroup_parts swp,
tbl_parts pa,
tbl_part_type pt,
tbl_swapgroups sw,
tbl_workorders wo
WHERE custom7 = 'somemodel'
AND swp.swapgroup_id IN (18,25)
AND sw.id = swp.swapgroup_id
AND pa.id = swp.part_id
AND pt.id = pa.parttype_id
AND wo.part_id = pa.id
) x
where x.rn=1
Also, ANSI JOIN syntax came out in 1992 - please use it :)

Related

Count in SQL server

select
hotel.hotel_name 'Hotel Name',
Address 'Address',
Description 'Description',
Contact_No 'Contact Number'
from hotel, customer_profile, booking_details where
customer_profile.email = booking_details.email
and hotel.hotel_name = booking_details.hotel_name
and booking_details.email = 'davidho#yahoo.com'
order by 1
I can't add images /:
So for example currently my result is
+-----------------------+
| Name | Address |
+-----------------------+
| Hotel1 | Beach Road1 |
| Hotel2 | Beach Road2 |
| Hotel2 | Beach Road2 |
+-----------------------+
I want it to remove the duplicates, and add a new column "Number of times" which indicate how many times it appeared.
I want it to be
+------------------------------------+
| Name | Address | No of Times |
+------------------------------------+
| Hotel1 | Beach Road1 | 1 |
| Hotel2 | Beach Road2 | 2 |
+------------------------------------+
You should use for your examples group by clause a below
select
hotel.hotel_name "Hotel Name",
Address, count(1) "No of Times"
from hotel, customer_profile, booking_details where
customer_profile.email = booking_details.email
and hotel.hotel_name = booking_details.hotel_name
and booking_details.email = 'davidho#yahoo.com'
group by hotel.hotel_name, Address
order by 1
First, learn proper join syntax, don't use single quote for column names, and use column aliases for all columns. Here is what I think your current query is doing.
select h.hotel_name as HotelName, h.Address. h.Description
cp.Contact_No
from booking_details bd join
hotel h
on h.hotel_name = bd.hotel_name join
customer_profile cp
on cp.email = bd.email
where bd.email = 'davidho#yahoo.com'
order by 1;
Next, to solve your question, just use group by. You can also eliminate the join to customer_profile, because I don't think that table gets used:
select h.hotel_name as HotelName, h.Address. count(*) as NumberOfTimes
from booking_details bd join
hotel h
on h.hotel_name = bd.hotel_name
where bd.email = 'davidho#yahoo.com'
order by 1;

SQL Server - Select data from one table based on a string value

I am wanting to look up data from one of my database tables based on a varchar stored in another table.
We have a table of Manufacturers (M) and a table of Parameters (P), and rather than having to have a parameter per Manufacturer (as there is a lot of crossover between 60% of them), we thought it would be cleaner to have parameters per manufacturer where required, and for the other ones just have a set of default parameters.
This means that I cannot store ManufacturerID in both tables and create a simple link, instead I need to link using the ManufacturerName.
So I need to know if it is possible to Link via ManufacturerName, and where there is no match look in the Parameters table (P) for Manufacturer 'Default'.
As part of the link, we are also including:
P.CategoryID = M.CategoryID AND (P.PriceFrom <= M.BasePrice AND
P.PriceTo >= M.BasePrice)
Here is the data structures:
Manufacturers (M):
ManufacturerID, ManufacturerName, CategoryID, BasePrice
Parameters (P)
CategoryID, ManufacturerName, PriceFrom, PriceTo, Percentage
Here is some sample data:
Manufacturers (M):
ManufacturerID | ManufacturerName | CategoryID | BasePrice
3 | Apple | 1 | 150.00
3 | Apple | 9 | 99.99
10 | HTC | 1 | 50.00
15 | Nokia | 1 | 25.00
19 | Samsung | 1 | 80.00
Parameters (P):
CategoryID | ManufacturerName | PriceFrom | PriceTo | Percentage |
1 | Samsung | 0.00 | 99.99 | 50% |
1 | Apple | 0.00 | 99.99 | 55% |
1 | Apple | 100.00 | 149.99 | 45% |
9 | Apple | 0.00 | 99.99 | 65% |
1 | Default | 0.00 | 99.99 | 60% |
So we still need to just return 1 result in each link.
Any suggestions of guidance much appreciated.
Thanks in advance.
As per the conditions you have posted a Left Join should serve the purpose:
select M.ManufacturerID, P.ManufacturerName, M.CategoryID
from Manufacturers M
left join Parameters P On P.CategoryID = M.CategoryID AND (P.PriceFrom <= M.BasePrice AND P.PriceTo >= M.BasePrice)
Please post your table structure here if I have missed something: SQL Fiddle
Without a table structure to work with is difficoult but something within the line of
SELECT m.name Manufacturer, p.name, p.value, p.Manufacturer alias
FROM Manufacturers m
INNER JOIN Parameter p ON (m.name = p.Manufacturer)
UNION ALL
SELECT m.name Manufacturer, p.name, p.value, p.Manufacturer alias
FROM Manufacturers m
LEFT JOIN Parameter p on p.Manufacturer = 'default'
WHERE m.name + p.name not in (SELECT m.name + p.name
FROM Manufacturers m
INNER JOIN Parameter p
ON (m.name = p.Manufacturer)
)
ORDER BY 1, 2
Can get what you need. The first part get you the linked part, the second part get the default value only for the parameters name that don't have already a match.
This is a SQLFiddle with a few data and the query
Ok, so it turns out this was another situation where I was overthinking the problem.
I managed to get this to work by having the following Select statement nested within another select:
(SELECT
TOP(1) Percentage
FROM
Parameters AS P
WHERE
P.CategoryID = R.CategoryID
AND (P.PriceFrom <= M.BasePrice AND P.PriceTo >= M.BasePrice)
AND (P.ManufacturerName = M.ManufacturerName OR P.ManufacturerName = 'Default')
ORDER BY
CASE WHEN P.ManufacturerName = 'Default' THEN 'ZZZZZ' ELSE P.ManufacturerName END
) AS Markup
Many thanks for your help.

Multiple select or distinct

I am new to sql so looking for a little help - got the first part down however I am having issues with the second part.
I got the three tables tied together. First I needed to tie tblPatient.ID = tblPatientVisit.PatientID together to eliminate dups which works
Now I need to take those results and eliminate dups in the MRN but my query is only returning one result which is WRONG - LOL
Query
select
tblPatient.id,
tblPatient.firstname,
tblPatient.lastname,
tblPatient.dob,
tblPatient.mrn,
tblPatientSmokingScreenOrder.SmokeStatus,
tblPatientVisit.VisitNo
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
and tblPatient.ID in(
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I')
Actual Results:
ID | firstName | LastName | DOB | MRN | SmokeStatus | VisitNO
12 | Test Guy | Today | 12/12/1023 | 0015396 | Never Smoker | 0013957431
Desired Results:
90 | BOB | BUILDER | 02/24/1974 | 0015476 | Former Smoker | 0015476001
77 | DORA | EXPLORER | 06/04/1929 | 0015463 | Never Smoker | 0015463001
76 | MELODY | VALENTINE | 09/17/1954 | 0015461 | Current | 0015461001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Current | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Never Smoker | 0015415001
32 | STRAWBERRY | SHORTCAKE | 07/06/1945 | 0015415 | Former Smoker | 0015415001
12 | Test Guy | Today | 12/12/1023 | 0015345 | Never Smoker | 0013957431
Anyone have any suggestions on how I go down to the next level and get all the rows with one unique MRN. From the data above I should have 5 in my list. Any help would be appreciated.
Thanks
If I had to guess -- The only thing that looks odd (but maybe it's OK) is that you're comparing patient.ID from your parent query to patient.mrn in the subquery.
Beyond that -- things to check:
(1)
Do you get all your patients with the inner query?
Select Distinct
tblPatient.mrn
From
tblPatient
where
isdate(DOB) = 1
and Convert(date,DOB) <'12/10/2000'
and tblPatientVisit.PatientType = 'I'
(2)
What is your patient type for the missing records? (Your filtering it to tblPatientVisit.PatientType = 'I' -- do the missing records have that patient type as well?)
Perhaps you need to invert the logic here. As in,
Select Distinct
patients.mrn1
From (select
tblPatient.id as id1,
tblPatient.firstname as firstname1,
tblPatient.lastname as lastname1,
tblPatient.dob as DOB1,
tblPatient.mrn as mrn1,
tblPatientSmokingScreenOrder.SmokeStatus as SmokeStatus1,
tblPatientVisit.VisitNo as VisitNo1,
tblPatientVisit.PatientType as PatientType1,
from
tblPatient,
tblPatientSmokingScreenOrder,
tblPatientVisit
Where
tblPatient.ID = tblPatientVisit.PatientID
and tblPatientVisit.ID = tblPatientSmokingScreenOrder.VisitID
) as patients
where
isdate(patients.DOB1) = 1
and Convert(date,patients.DOB1) <'12/10/2000'
and patients.PatientType1 = 'I');
Cleaned it up a bit and I think they were right. MRN wont match patient id, at least not from your example data. You should not need an inner query. This query should give you what you want.
SELECT DISTINCT
p.id,
p.firstname,
p.lastname,
p.dob,
p.mrn,
s.SmokeStatus,
v.VisitNo
FROM
tblPatient p
JOIN tblPatientVisit v ON p.id = v.patientId
JOIN tblPatientSmokingScreenOrder s ON v.id = s.visitId
WHERE
isdate(p.DOB) = 1
AND CONVERT(date,p.DOB) <'12/10/2000'
AND v.PatientType = 'I'

SQL Order By Within A Count(Distinct)

I have the following tables:
filetype1
F1_ID | F1_ORDR | FILENAME
1 | 1 | file1.txt
2 | 2 | file2.txt
3 | 3 | file3.txt
4 | 2 | file4.txt
5 | 4 | file5.txt
filetype2
F2_ID | F2_ORDR | FILENAME
1 | 1 | file6.txt
2 | 2 | file7.txt
3 | 4 | file8.txt
ordr
OR_ID | OR_VENDOR
1 | 1
2 | 1
3 | 1
4 | 1
vendor
VE_ID | VE_NAME
1 | Company1
My goal is to have a list of vendors and a count of the number of orders where a file is connected for each type. For example, the end result of this data should be:
VENDOR | OR_CT | F1_CT | F2_CT
Company1 | 4 | 4 | 3
Because at least 1 type1 file was attached to 4 distinct orders and at least 1 type2 file was attached to 3 distinct orders. Currently my SQL code looks like this:
SELECT vendor.ve_id, vendor.ve_name,
(SELECT COUNT(or_id)
FROM ordr
WHERE ordr.or_vendor = vendor.ve_id) as OR_COUNT,
(SELECT COUNT(DISTINCT f1_order)
FROM filetype1 INNER JOIN ordr ON filetype1.f1_ordr = ordr.or_id
WHERE ordr.or_vendor = vendor.ve_id) as F1_CT,
(SELECT COUNT(DISTINCT f2_ordr)
FROM filetype2 INNER JOIN ordr ON filetype2.f2_ordr = ordr.or_id
WHERE ordr.or_vendor = vendor.ve_id) as F2_CT
FROM vendor
ORDER BY vendor.ve_name
Unfortunately this yields the following results:
VENDOR | OR_COUNT | F1_COUNT | F2_COUNT
Company1 | 4 | 5 | 3
My only guess is that because I'm using COUNT(DISTINCT) the COUNT is automatically assuming the DISTINCT is ordering by F1_ID instead of by F1_ORDR
If anyone can assist me on how to tell the COUNT(DISTINCT) to order by F1_ORDR that would be most helpful. I have searched the vast internet for a solution but its hard to explain what I want to a search engine, forums, etc. My database uses Microsoft SQL Server. My knowledge of database management is almost completely self taught, so I'm just glad I made it this far on my own. My expertise is in web design. Thank you for your time.
Your SQL yields the result you want for me.
Two pieces of advice
Order is a bad name for a table - it conflicts with a reserved word, and will cause you no end of hassle
You should join your tables like so
FROM filetype1
inner join [order]
on filetype1.f1_order = or_id
rather than using a where clause
Perhaps try this instead
select
vendor.VE_ID, vendor.VE_NAME,
count(distinct or_id),
count(distinct f1_order),
count(distinct f2_order)
from
vendor
left join [order]
on vendor.VE_ID = [order].OR_VENDOR
inner join filetype1
on [order].OR_ID = filetype1.F1_ORDER
left join filetype2
on [order].OR_ID = filetype2.F2_ORDER
group by
vendor.VE_ID, vendor.VE_NAME
Try this:
SELECT
vdr.VE_NAME
,COUNT(DISTINCT OR_ID) AS OR_ID
,COUNT(DISTINCT ft1.F1_ORDER) AS FT1_COUNT
,COUNT(DISTINCT ft2.F2_ORDER) AS FT2_COUNT
FROM
vendor vdr
LEFT OUTER JOIN [order] odr
ON vdr.VE_ID = odr.OR_VENDOR
INNER JOIN filetype1 ft1
ON odr.OR_ID = ft1.F1_ORDER
LEFT OUTER JOIN filetype2 ft2
ON odr.OR_ID = ft2.F2_ORDER
GROUP BY
vdr.VE_ID
,vdr.VE_NAME
I will propose you this:
Merge filetype1 and filetype2 tables in one table(filetype) and add another field named - f_type(for instance) of type INT or TINTYINT to store the filetype (1 or 2). This has the benefits of painlessly adding another filetype later
Now the query will look something like this:
SELECT
vendor.ve_name,
count(DISTINCT filetype.f_order),
filetype.f_type
FROM
filetype
INNER JOIN `order`
ON filetype.f_order = `order`.or_id
INNER JOIN vendor
ON `order`.or_vendor = vendor.ve_id
GROUP BY vendor.ve_id,filetype.f_type
This will give the count of orders for filetype.
For the total orders just add another query:
SELECT count(*) FROM `order`

Complex join with coalesce

I have a table that I am stuffing demographic info into and then using dynamic sql to build a table from that. The demographic info comes from surveys and some of the surveys have checkboxes. With checkboxes people can select multiple values.
So I need to enter all the choices as a comma seperated list.
CREATE TABLE Demographics
(
QID NVARCHAR(15)
,userid NVARCHAR(50)
,question NVARCHAR(800)
,choice NVARCHAR(1000)
)
...
...
--Demographics(QID,userid,question,choice)
--'Insert checkbox (type 5)
INSERT INTO Demographics
SELECT CAST(q.QID AS NVARCHAR(15))
,ri.userid
,q.QuestionText
,ac.Choice
FROM ResponseInfo ri --response details
JOIN Responses r ON ri.ResponseID = r.ResponseID --actual response
JOIN Questions q ON r.QID = q.QID --question info
JOIN AnswerChoices ac ON r.QID = ac.QID --answer choice text
WHERE (q.QuestionTypeID = 5 AND q.QID = ac.QID
AND r.IsOther = 0
AND q.QID = 16
)
AND ri.userid IN (SELECT userid FROM #Users) AND r.Response = ac.Sequence
ORDER BY ri.userid
...
dynamic sql stuff
...
EXEC sp_exesql #sql
My results look like this:
users | question_15 | choice_15 | question_16 | choice_16 |
bill | age? | 37 | favorite color? | red |
bill | age? | 37 | favorite color? | green |
But it needs to be:
users | question_15 | choice_15 | question_16 | choice_16 |
bill | age? | 37 | favorite color? | red,green |
I tried doing
,COALESCE(ac.Choice + ',','') + ac.Choice
It gave me
bill | age? | 37 | favorite color? | red,red |
Can anyone help me sort this out?
It looks like you are using SQL Server. If you're using a recentish version of SQL Server (e.g., SQL Server 2005 or later), you'd likely be better off storing your data as XML.
That lets you use XPATH/XQUERY in SQL to manipulate the XML data to get what you want. I think you'll find that easier to do.
http://www.simple-talk.com/sql/learn-sql-server/sql-server-xml-cribsheet/
http://www.simple-talk.com/sql/t-sql-programming/beginning-sql-server-2005-xml-programming/
Found this.
Very helpful. My code could probably use some cleaning up.