I need help for building a SQL-statement. The Database-Schema looks like this:
I did prepare the following SQL-Fiddle, which contains sample-data:
http://sqlfiddle.com/#!9/831bab/1
As for the sample-data in the SQL-Fiddle, I want to query for the computername "Client02" and want to get the following result:
Wanted result 1
PrinterName | PrintServer | PrinterActive | ComputerActive | isDefaultPrinter
PRT01_Zentral | DC01 | True | True | False
PRT02_BH | DC01 | True | True | True
As for the sample-data in the SQL-Fiddle, I want to query for the computername "Client01" and want to get the following result:
Wanted result 2
PrinterName | PrintServer | PrinterActive | ComputerActive | isDefaultPrinter
PRT01_Zentral | DC01 | True | True | True
As you see, I need to join all the tables and add something like a helper-column, which contains information about the default-printer. (True/False)
I started to build up the query, but I don't know how to proceed ...
SELECT printers.PrinterName, printers.PrintServer, printers.PrinterActive
FROM computermapping
LEFT JOIN computers ON computermapping.ComputerID = computers.ComputerID
LEFT JOIN printers ON computermapping.PrinterID = printers.PrinterID
LEFT JOIN computerdefaultprinter ON computers.ComputerID = computerdefaultprinter.ComputerID
WHERE computers.ComputerName = "Client02"
I think my request contains all the information, which is needed. The SQL-Fiddle has sample-data to easily reproduce it. The WantedResults should show the target clearly.
EDIT:
DBMS: MySQL
You could use the following query to get the result that you need
SELECT printers.PrinterName,
printers.PrintServer,
printers.PrinterActive,
computers.ComputerActive,
CASE
WHEN computerdefaultprinter.PrinterID IS NULL THEN "false"
ELSE "true"
END AS isDefaultPrinter
FROM computermapping
LEFT JOIN computers
ON computermapping.ComputerID = computers.ComputerID
LEFT JOIN printers
ON computermapping.PrinterID = printers.PrinterID
LEFT JOIN computerdefaultprinter
ON computers.ComputerID = computerdefaultprinter.ComputerID
AND printers.PrinterID = computerdefaultprinter.PrinterID
WHERE computers.ComputerName = "Client02"
I've only added CASE...WHEN statement and modified join condition of your original query.
But I think instead of using table computerdefaultprinter, why don't you add column IsDefaultPrinter to table computermapping.
CREATE TABLE `computermapping` (
`ComputerMappingID` int(11) NOT NULL,
`PrinterID` int(11) NOT NULL,
`ComputerID` int(11) NOT NULL,
`IsDefaultPrinter` int(1) NOT NULL DEFAULT 0,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
What I did was add a if statement in your query, comparing the inner result (that can only be 1) to your outter select. There is a better way of achieving this probably but this answer reflects the queryresult's that you've asked.
Edit: I'm assuming only a default printer per computer.
Are you sure the wanted result 2 is correct? Because in the database, records are saying computer1 has 1 printerid (1) that is the default and that computer2 has 2 printers (1 and 2) and 2 is default.
SELECT printers.PrinterName,
printers.PrintServer,
printers.PrinterActive,
IF (
(SELECT computerdefaultprinter.printerid
FROM computerdefaultprinter
WHERE computerdefaultprinter.computerid = computermapping.computerid) = computermapping.printerid,
'true',
'false') AS isDefaultPrinter
FROM computermapping
LEFT JOIN computers ON computermapping.ComputerID = computers.ComputerID
LEFT JOIN printers ON computermapping.PrinterID = printers.PrinterID
LEFT JOIN computerdefaultprinter ON computers.ComputerID = computerdefaultprinter.ComputerID
WHERE computers.ComputerName = "Client02"
Related
I have a table which list available items, when user click on any item it will insert in added_items table. Now my problem is I want to use join to select all items that any user has not added. My current query doesn't show items if one user has added it.
items
name | type | id | user
-------|------|----|------------------
JAVA | A | 1 | SYSTEM
PHP | A | 2 | SYSTEM
HTML | B | 3 | USER1
added_items
item_id | user
----------|--------------
1 | peter
My query
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.user = it.user
#on ait.item_id = it.id
WHERE it.type = "A"
AND ait.user IS NULL
The second query I tried
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.item_id = it.id
WHERE it.type = "a"
AND ait.user != "peter"
Expected result
when current user is peter I want to retrieve only PHP as peter has added JAVA.
But if current user isn't on added_items the retrieve all record.
Add fiddle http://sqlfiddle.com/#!9/3761e40
SELECT *
FROM items
WHERE NOT EXISTS ( SELECT NULL
FROM added_items
WHERE items.id = added_items.item_id
-- AND added_items.user = "peter"
)
-- AND items.type = 'A'
fiddle
You can try:
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.item_id = it.id
WHERE ait.item_id IS NULL
I have a couple of tables, one with source data which I'll call SourceData and another which defines overridden values for a given user if they exist called OverriddenSourceData.
The basic table format looks something this like:
SourceData
| source_id | payload |
--------------------------------
| 1 | 'some json' |
| 2 | 'some more json' |
--------------------------------
OverriddenSourceData
| id | source_id | user_id | overrides
| 1 | 2 | 4 | 'a change' |
------------------------------------------
For a given user, I'd like to return all the Source data rows with the overrides column included. If the user has overridden the source then the column is populated, else it is null.
I started by executing a left join and then including a condition for checking the user like so:
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
WHERE user_id = 4
but then source rows that weren't overridden wouldn't be included ( it was acting like an inner join) (e.g source id 1)
I then relaxed the query and used a strict left join on source_id.
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
# WHERE user_id = 4
This can return more data than I need though (e.g other users who have overridden the same source data) and then I have to filter programatically.
It seems like I should be able to craft a query that does this all the DB level and gives me what I need. Any help?
You should add your condition on LEFT JOIN clause, if you use WHERE, mysql will do it with INNER JOIN, so try this;)
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
AND B.user_id = 4
I have two tables with the following structures:
exp_hotel
hot_id | hot_webid | hot_name | hot_starrating | hot_brandbool | hot_latitude | hot_longitude
exp_result
res_id | res_idHotel | res_rank | res_price | res_userRating | res_oldPrice | res_posa | res_date | res_date | res_que_id
res_posa has sometimes either the value 'xxx' or the value 'yyy'.
If it has the value 'xxx', the SELECT should be something like:
SELECT * FROM exp_hotel JOIN exp_result ON hot_id = res_idHotel
And if res_posa value is 'yyy' than the SELECT would be:
SELECT * FROM exp_hotel JOIN exp_result ON hot_webid = res_idHotel
Is there a way how to create a query wich would select everything with the correct JOIN structure directly from MySQL without going through some PHP arrays and so on?
You can use conditional join like below.
SELECT * FROM exp_hotel JOIN exp_result ON
(res_posa = 'XXX' and hot_id = res_idHotel)
OR
(res_posa = 'YYY' and hot_webid = res_idHotel);
Mock up fiddle here.
I have two tables reports & viewedids
the first one stores data and the second one stores user IDs that viewed data:
viewedids:
+-------+------+
| uid | rid |
+-------+------+
| 2 | 5 |
+-------+------+
each (uid,rid) means the uid has viewd rid
I want to select * from reports table and add view state (0 or 1) for current user to it. (A JOIN statement)
How can I do this?
You can use a LEFT JOIN:
SELECT reports.*, viewedids.uid IS NOT NULL as view_state
FROM
reports LEFT JOIN viewedids
ON reports.id = viewedids.rid
AND viewedids.uid = #current_user
This will return all reports, and will try to join reports table with viewedids ON reports.id = viewedids.rid AND viewedids.uid = #current_user. If the join succedes, viewedids.uid will be not null, and viewedids.uid IS NOT NULL will be evaluated to 1. It will be evaluated 0 otherwise.
Please see fiddle here.
Ok I have a few tables tables. I am only showing relevant fields:
items:
----------------------------------------------------------------
name | owner_id | location_id | cab_id | description |
----------------------------------------------------------------
itm_A | 11 | 23 | 100 | Blah |
----------------------------------------------------------------
.
.
.
users:
-------------------------
id | name |
-------------------------
11 | John |
-------------------------
.
.
.
locations
-------------------------
id | name |
-------------------------
23 | Seattle |
-------------------------
.
.
.
cabs
id | location_id | name
-----------------------------------
100 | 23 | Cool |
-----------------------------------
101 | 24 | Cool |
-----------------------------------
102 | 24 |thecab |
-----------------------------------
I am trying to SELECT all items (and their owner info) that are from Seattle OR Denver, but if they are in Seattle they can only be in the cab NAMED Cool and if they are in Denver they can only be in the cab named 'thecab' (not Denver AND cool).
This query doesn't work but I hope it explains what I am trying to accomplish:
SELECT DISTINCT
`item`.`name`,
`item`.`owner_id`,
`item`.`description`,
`user`.`name`,
IF(`loc`.`name` = 'Seattle' AND `cab`.`name` = 'Cool',1,0) AS `cab_test_1`,
IF(`loc`.`name` = 'Denver' AND `cab`.`name` = 'thecab',1,0) AS `cab_test_2`,
FROM `items` AS `item`
LEFT JOIN `users` AS `user` ON `item`.`owner_id` = `user`.`id`
LEFT JOIN `locations` AS `loc` ON `item`.`location_id` = `loc`.`location_id`
LEFT JOIN `cabs` AS `cab` ON `item`.`cab_id` = `cabs`.`id`
WHERE (`loc`.`name` IN ("Seattle","Denver")) AND `cab_test_1` = 1 AND `cab_test_2` = 1
I'd rather get rid of the IFs is possible. It seems inefficent, looks clunky, and is not scalable if I have a lot of location\name pairs
Try this:
SELECT DISTINCT
item.name,
item.owner_id,
item.description,
user.name
FROM items AS item
LEFT JOIN users AS user ON item.owner_id = user.id
LEFT JOIN locations AS loc ON item.location_id = loc.id
LEFT JOIN cabs AS cab ON item.cab_id = cabs.id
WHERE ((loc.name = 'Seattle' AND cab.name = 'Cool')
OR (loc.name = 'Denver' AND cab.name = 'thecab'))
My first thought is to store the pairs of locations and cab names in a separate table. Well not quite a table, but a derived table generated by a subquery.
You still have the problem of pivoting the test results into separate columns. The code can be simplified by making use of mysql boolean expressions, which get rid of the need for a case or if.
So, the approach is to use the same joins you have (although left join is not needed because the comparison on cab.name turns them in to inner joins). Then add a table of the pairs you are looking for, along with the "test name" for the pair. The final step is an explicit group by and a check whether conditions are met for each test:
SELECT i.`name`, i.`owner_id`, i.`description`, u.`name`,
max(pairs.test_name = 'test_1') as cab_test_1,
max(pairs.test_name = 'test_2') as cab_test_2
FROM `items` i LEFT JOIN
`users` u
ON i.`owner_id` = u.`id` LEFT JOIN
`locations` l`
ON i.`location_id` = l.`location_id` left join
`cabs` c
ON i.`cab_id` = c.`id` join
(select 'test_1' as testname, 'Seattle' as loc, 'cool' as cabname union all
select 'test_2', 'Denver', 'thecab'
) pairs
on l.name = pairs.name and
l.cabname = c.name
group by i.`name`, i.`owner_id`, i.`description`, u.`name`;
To add in additional pairs, add them into the pairs table along, and add an appropriate line in the select for the test flag.