SQL Server - Query with Join and mutiple conditions - sql

I'm trying to query four table as below:
Table1: Users
User | Name
-------------
01 | Phil
-------------
02 | John
-------------
03 | Marc
-------------
04 | Rob
Order: Integer and Incremental / Name: varchar
Table2: Status
Status | Description
--------------------
01 | Canceled
--------------------
02 | Confirmed
--------------------
03 | Bulding
--------------------
.. | .....
--------------------
15 | Finished
Status: Integer and Incremental / Description: varchar
Table3: Build
Order | Date | Place
----------------------------
01 | 01/01/2014 | MG
----------------------------
02 | 02/02/2014 | SP
----------------------------
05 | 03/03/2014 | BA
Order: Integer / Date: Date / Place: Varchar
Table4: Orders
Order | User | Status
-----------------------
01 | 02 | 01
-----------------------
02 | 01 | 11
-----------------------
03 | 03 | 15
-----------------------
04 | 01 | 03
-----------------------
05 | 04 | 02
Order: Integer and Incremental / User: Integer / Status: Integer
I have to query Table 4 to show all orders (except status 1,15) join with table 01, table 02 and table 03 ordering by date at table 03. The problem is table 03 not always have a row with the order number and the this order doesn't show at query.
I need a result like this:
Query Result:
Order | User | Name | Status | Description | Date | Place
----------------------------------------------------------------
02 | 01 | Phil | 11 | Painting | 02/02/2014 | SP
----------------------------------------------------------------
05 | 04 | Rob | 02 | Confirmed | 03/03/2014 | BA
----------------------------------------------------------------
04 | 01 | Phil | 03 | Bulding | |
Thanks for the help !!!

Use "LEFT OUTER JOIN" for table 3. That will return all the records in the other tables, the matches in table 3, and if table 3 doesn't match, it will show up blank.
For example:
SELECT *
FROM Orders
LEFT OUTER JOIN Build ON Order.Order = Build.Order
This will return all of the results for Orders and the matches from Build. Note, the table you want to keep all the records from must go on the LEFT side of the ON statement (ON Order.Order = Build.Order).
More info: http://technet.microsoft.com/en-us/library/ms187518%28v=SQL.105%29.aspx

Related

SELECT Top values for each records

I have been battling through this query/query design for sometime now and I thought it's time to ask the experts! Here's my table results:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
01 | Engaged | 11/4/2018 |
03 | Contacted | 16/4/2018 |
05 | Surveyed | 04/3/2017 |
05 | No Contact | 05/3/2017 |
How do I get it to return top/newest value for each ID:
ID | Status | date |
---------------------------------
05 | Returned | 20/6/2018 |
03 | Sent | 12/5/2018 |
01 | Pending | 07/6/2018 |
I've tried group by, TOP 1, Distinct and results still not what I wanted. Also, displaying the results by top 5% is won't do either as the ID can be more than just 3 types.
My QUERY below:
INSERT INTO TmpAllcomsEmployee ( StatusID, EmployeeID, CommunicationDate )
SELECT DISTINCT CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID,
Max(CommunicationLog.CommunicationDate) AS MaxOfCommunicationDate
FROM CommunicationLog RIGHT JOIN TmpAllcomsEmployee ON
CommunicationLog.EmployeeID = TmpAllcomsEmployee.EmployeeID
GROUP BY CommunicationLog.StatusID, TmpAllcomsEmployee.EmployeeID
ORDER BY Max(CommunicationLog.CommunicationDate) DESC;
One method is a correlated subquery:
select cl.*
from CommunicationLog as cl
where cl.date = (select max(cl2.date)
from CommunicationLog as cl2
where cl2.EmployeeID = cl.EmployeeID
);
This gets the most recent record for each employee in CommunicationLog. You can join in the other table if you really need it. It does not seem unnecessary unless you are using it for filtering.

Access Concatenating Values in a Query

I have a query, [Query1], with employee names, projects, days, months, and years.
In another query, [Query2], I take all the values and put them into a cross table. My rows are "Year, Month, Employee." My column is "Day." My values are Projects.
The problem is that for one date, there may be more than one project assigned to an employee.
When I attempt to put the projects as values into a table using IIf(Count(*)>0,[Project],""), I get an error because there may be more than one possible value for the project, and access doesn't know which one to choose.
I need a way to Concatenate the values if there is more than one Project.
Ex:
[Query1]
Bill | CC555 | 28 | 03 | 2014
Jim | CC999 | 29 | 03 | 2014
Jim | CC555 | 29 | 03 | 2014
John | CC555 | 29 | 03 | 2014
[Query2]
Year | Month | Employee | 1 | 2 | 3 | ... | 27 | 28 | 29 | 30 | 31
2014 | 03 | Bill | - | - | - | ... | - | CC555 | - | - | -
2014 | 03 | Jim | - | - | - | ... | - | - | CC555 + CC999 | - | -
2014 | 03 | John | - | - | - | ... | - | - | CC555 | - | -
Aside: [Query1] is dynamic and could have duplicate dates deleted or added to it, so [Query2] values must change accordingly.
one simple example,you have to make it dynamic,in real scenrio no need of table variable or CTE if using dynamic sql.i think no need of dynamic,just hard code from 1 to 31
;With CTE as
(
select 'Bill' Employee ,'CC555' codes,28 dd,03 mm ,2014 yrs union all
select 'Jim ','CC999', 29 , 03 , 2014 union all
select 'Jim ','CC555', 29 , 03 , 2014 union all
select 'John','CC555', 29 , 03 , 2014
)
select yrs,mm,Employee,isnull([28],'-')[28],[29],[30] from
(select Employee,dd,mm,yrs
,stuff((select ','+codes from cte b where b.Employee=a.Employee for xml path('')),1,1,'')codes
from cte a ) src
pivot (min(codes) for dd in([28],[29],[30])) pvt
By using the function given here allenbrowne.com/func-concat.html, and following the example given here http://www.access-programmers.co.uk/forums/showthread.php?t=234291, I was able to solve the problem.

Count number of records with matching values in separate fields

I have a table (myTable) as such:
id | name | orig_id
----+-------+--------
01 | Bill | -
02 | Tom | 01
03 | Sam | 01
04 | Alex | 02
05 | Phil | -
06 | Bob | 01
I'd like a query that returns each record but with an added column containing the count of other rows that have an orig_id equal to the current row's id.
The resulting table would look like this:
id | name | orig_id | mycount
----+-------+---------+--------
01 | Bill | - | 3
02 | Tom | 01 | 1
03 | Sam | 01 | 0
04 | Alex | 02 | 0
05 | Phil | - | 0
06 | Bob | 01 | 0
I've tried the following query, but get no results:
SELECT *, COUNT(t.name) AS mycount
FROM "myTable" AS t
WHERE t.id=t.orig_id
GROUP BY t.id;
How can I achieve the desired results?
You can do this with a join and aggregation:
SELECT t.*, tsum.mycount
FROM myTable t join
(select orig_id, count(name) as mycount
from myTable
group by orig_id
) tsum
on t.id = tsum.orig_id;
A simple left join with count will do it:
select t.id, t.name, t.orig_id, count(o.id) mycount
from myTable t
left join myTable o on t.id = o.orig_id
group by t.id, t.name, t.orig_id
See a live demo on SQLFiddle that produces this result:
ID NAME ORIG_ID MYCOUNTÂ
01 Bill (null) 3
02 Tom 01 1
03 Sam 01 0
04 Alex 02 0
05 Phil (null) 0
06 Bob 01 0

Order sql results using a Count() value from another table

assuming we have a users table like this:
ID | USERNAME | STATUS |
01 | Aname | 1 |
02 | Bname | 1 |
03 | Cname | 2 |
04 | Dname | 1 |
there are also two other tables, where, for each user, records the items that the users "has" for istance, video and photos, lets assume the video table is like this:
ID | USER | VIDEO |
01 | 01 | aaaa |
02 | 01 | bbbb |
03 | 02 | cccc |
04 | 02 | dddd |
05 | 03 | eeee |
06 | 03 | ffff |
07 | 03 | gggg |
the same for the photos:
ID | USER | PHOTO |
01 | 01 | aaaa |
02 | 02 | cccc |
03 | 02 | dddd |
04 | 03 | eeee |
05 | 03 | ffff |
06 | 03 | gggg |
now, i'm trying to order the results of the first table, on the STATUS field, so the users with status 2 will go at the end (or beginning) of the results, but i would like to order the others by the fact that they have, or have not videos or photos. Actually for all the users in the status 1 I check if they have video AND photos and display a message like "warning, you have no videos" or something, i would like also to order all the users on the status basis AND on the fact that they have or not photos or video... something like:
SELECT id,username,status,NumOfPhotos,NumOfVideos order by status ASC, numOfPhotos ASC, NumOfVideos DESC
where NumOfPhotos, for example is SELECT COUNT(*) FROM PHOTOS WHERE USER = USERS.ID
Is that possible? is that possible in a single statement?
This is an example on SQL Server, but something similar should work well on other RDBMS
SELECT
id, username, status, COALESCE(NumOfPhotos,0) AS NumOfPhotos,COALESCE(NumOfVideos,0) AS NumOfVideos
FROM dbo.Users u
LEFT JOIN (SELECT [USER], COUNT(*) AS NumOfPhotos FROM dbo.Photos GROUP BY [USER]) ph ON ph.[USER] = u.ID
LEFT JOIN (SELECT [USER], COUNT(*) AS NumOfVideos FROM dbo.Videos GROUP BY [USER]) vd ON vd.[USER] = u.ID
ORDER BY status ASC, numOfPhotos ASC, NumOfVideos DESC
SQLFiddle

SQL, select in tables

Hey I don't know how to do it....
Its a homework: List the code and the consumers who bought cars only 'Argentina' country.
Table sell:
customer | resell | veicle | date | value
---------+---------+-----------+------------+----------
02 | 01 | 03 | 2010-02-05 | 17500.00
04 | 02 | 01 | 2010-01-07 | 28000.00
01 | 03 | 08 | 2010-02-15 | 28000.00
02 | 03 | 02 | 2010-03-12 | 42000.00
03 | 04 | 06 | 2010-02-06 | 11500.00
03 | 02 | 05 | 2010-01-25 | 22100.00
01 | 01 | 04 | 2010-01-21 | 15500.00
Table customer:
cod | name | lastname
--------+------------+------------
01 | Jose | Alves
02 | Paulo | Cunha
03 | Maria | DPaula
04 | Joana | Silveria
Table veicle:
cod |manufacturer| model | year | country | price
--------+------------+-----------------+------+-----------+----------
01 | 01 | Gol | 2000 | Brasil | 25000.00
02 | 01 | Golf | 2005 | Argentina | 39000.00
03 | 04 | Ford Ka | 1990 | Brasil | 15000.00
04 | 03 | Corsa Seda | 1995 | Brasil | 12500.00
05 | 04 | Fiesta | 2003 | Argentina | 20000.00
06 | 03 | Corsa Seda | 1995 | Argentina | 10000.00
07 | 05 | Palio | 2002 | Brasil | 15000.00
08 | 05 | Siena | 2006 | Brasil | 26000.00
I guess it to start:
SELECT customer.cod, customer.name
FROM sell, customer
WHERE (SELECT cod
FROM veicle
WHERE veicle.country = 'Argentina') = sell.veicle;
To select only the argentine cars...
Please guide-me to the answer.
SELECT c.*
FROM customer c
WHERE EXISTS (
SELECT 1
FROM sell s
JOIN veicle v ON v.cod = s.veicle
WHERE s.customer = c.cod
AND v.country = 'Argentina'
)
AND NOT EXISTS (
SELECT 1
FROM ...
);
I'll leave the rest for you, as this is homework. Fill in for ... to exclude customers that have bought vehicles that are not from Argentina - very similar to the first EXISTS clause. If you have understood the first, you can complete the rest.
Try this
SELECT DISTINCT customer.cod, customer.name || customer.lastname FROM customer, veicle, sell WHERE customer.cod = sell.customer AND veicle.cod = sell.veicle AND veicle.country = 'Argentina'
Look into table joins. That way instead of doing a subquery (what is in your where statement) you can instead join on the tables (kindof like your From clause but you should specify what it joins on) and then in your where you can just put veicle.country = 'Argentina'.
And FYI veicle is spelled wrong. It should be vehicle.
Try this :
SELECT c.cod, c.name,c.last_name,v.model
FROM sell as s JOIN customer as c JOIN veicle as v ON s.veicle = v.cod and s.customer = c.cod
WHERE v.country = 'Argentina'
WITH minima AS (
SELECT DISTINCT s.customer
, MIN(v.country) AS mi
, MAX(v.country) AS ma
FROM sell s
JOIN veicle v ON s.resell = v.cod
GROUP BY s.customer
)
SELECT cu.* FROM customer cu
JOIN minima mm ON mm.customer = cu.cod
WHERE mm.mi = 'Argentina'
AND mm.ma = 'Argentina'
;