How do I write code in SQL for following example - mysql

I have two tables, BOQ and DPR
Table : BOQ
ID | Buidling| Activity |Plan_Start_Date|Actual_Start_Date
1 |A-1 |Shuttering|02-02-2019 |15-02-2019
2 |A-2 |Shuttering|13-02-2019 |13-02-2019
Table : DPR
ID | Buidling| Activity |Date |
1 |A-1 |Shuttering|15-02-2019 |
I need to write an expression for column Actual_Start_Date such that when Building and Activity columns are matched in both tables then it should display the date in DPR table as Actual_Start_Date (in above case 15-02-2019 is Actual_Start_Date of id 1 in BOQ as the table and activity columns are matched).
If there is no matching value then Actual_Start_Date should show Plan_start_Date as in ID 2 of BOQ

You want a left join:
select . . ., -- whatever other columns you want
coalesce(dpr.date, boq.actual_start_date) as actual_start_date
from boq left join
dpr
on boq.building = dpr.building and
boq.activity = dpr.activity;
You can easily turn this into an update:
update boq join
dpr
on boq.building = dpr.building and
boq.activity = dpr.activity
set boq.actual_start_date = coalesce(dpr.date, boq.actual_start_date) ;

Related

Can I craft a statement to return records where (attribute A = A1 and attribute B = B1) OR (attrbt A = A2 and attrbt B = B2) OR etc etc?

User has given me a table of vendor #s and Invoice #s, and wants a query to find the documents with those attributes. Tried just giving him:
select * from document.docdata
join document.documents.vendor #s
join document.documents.invoice #s
Where
vendor # in (paste in column A from his table)
AND
invoice # in (paste in column b from his table)
But that didn't do the trick, because he's wanting to see the docs whose vendor# and invoice# match the rows of the table, as in vendor#, invoice# = A1, B1. My first question was "Why not just search by the invoice# and be done with it?"
But turns out the invoice numbers aren't unique.
So I'm needing a better way of writing this:
Select * from table
join vendor #s
join invoice #s
Where
(Vendor#=A1 AND Invoice#=B1)
OR
(Vendor#=A2 AND Invoice#=B2)
....
OR
(Vendor#=A652 AND Invoice#=B652)
For sample data, here's an example with the first 10 items from the user. I have this data in csv format.
A | B
---------------------
354055 | 1637
259769 | 2112
259769 | 2314
153060 | 47185
174829 | 63486
297719 | 4994-033017
203110 | 1360
292193 | 2058-09-1271
202308 | 60513
286641 | 1975
So I need the records that match both Company 354055 and Invoice 1637, as well as both Company 259769 and Invoice 2112, plus both Company 259769 and Invoice 2314, etc.
EDIT: I ended up just using excel to get 659 lines of "(Vendor#=x AND Invoice#=y) OR". Probably could run faster but it works, so off to production it goes.
MySQL supports tuple syntax:
Select *
from table join
vendor #s
on . . . join
invoice #s
on . . .
Where (#Vendor#, Invoice#) in ( (A1, B1), (A2, B2), . . . )
This is a rough answer, since we don't have good sample data or column names, but the general idea is, since you have an external table that matches invoice #s to vendor #s, you should import that data into a temporary table. Then you can join against the table for records where both conditions match in an efficient way.
There are also VALUES() expressions (formally: Table Value Constructors). You could use this to generate your query with a little less code: create the expression for your data as part of the SQL string, and then JOIN against that expression to accomplish the filter.
SELECT d.*
FROM document.docdata d
INNER JOIN (
VALUES
ROW(354055,'1637'),
ROW(259769,'2112'),
ROW(259769,'2314'),
ROW(153060,'47185')
-- etc
) filter on filter.invoice = d.invoice and filter.company = d.company

SQL Joins - Gather all from RIGHT table

I have two tables:
user-data:
id | userID | keyID | val
1 99 1 1
user-data-keys
id | key
1 is-staff
2 description
3 image
Now, when I run the following SQL, I get the desired output:
SELECT `key`,`val` FROM `user-data` RIGHT JOIN `user-data-keys` ON `user-data`.`keyID` = `user-data-keys`.`id`;
Which produces:
key | val
is-staff 1
description NULL
image NULL
Which is exactly what I want. However when I add a WHERE clause to the SQL:
SELECT `key`,`val` FROM `user-data` RIGHT JOIN `user-data-keys` ON `user-data`.`keyID` = `user-data-keys`.`id` WHERE `userID` = 99;
I only get the one row with is-staff in it. Which I understand, as I asked for only rows with userID = 99. However I am planning on storing lots of different user's information in the one user-data table, and I want to know if they have a NULL value for each of the keys. So how can I achieve this? I know it's got to be some kind of fancy join that I am not aware of.
So to clarify: i need the output like this:
key | val
is-staff 1
description NULL
image NULL
When using a WHERE userID = 99. Currently I only get one row whilst using a WHERE clause.
Move the predicate from the WHERE clause to the join:
SELECT `key`,`val` FROM `user-data` RIGHT JOIN `user-data-keys` ON `user-data`.`keyID` = `user-data-keys`.`id` and `userID` = 99;
If you want to get rows which are not matched then you can add where conditions with join like " ON user-data.keyID = user-data-keys.id AND userID = 99 " instead of " WHERE userID = 99 ",
SELECT `key`,`val`
FROM `user-data`
RIGHT JOIN `user-data-keys` ON `user-data`.`keyID` = `user-data-keys`.`id` AND `userID` = 99
WHERE 1;

How to dynamically create a pivot table on MySQL

I'm having difficulties creating the result i want on a specific situation.
I have a two tables:
1: sales by warehouse:
+-------------+---------------+--------------+
warehouse | type -------- | value
+-------------+---------------+--------------+
A--------------XX-------------234234----------
A-------------- YY------------ 234343--------------
A-------------- ZZ------------ 534534--------------
B-------------- XX------------ 234432--------------
B-------------- YY------------ 767563--------------
B-------------- ZZ------------ 312332--------------
c-------------- XX------------ 234234--------------
....
2: users by warehouse:
user--------|---warehouse
john--------|-- A
john--------|-- B
john--------|-- C
peter-------|-- A
Daniel------|-- C
Kim---------|-- B
Kim---------|-- C
....
So i created this query:
select a.warehouse, type, value from sales_by_warehouse A
left join users_warehouse B
ON A.warehouse=B.warehouse
where b.user = 'user_logged_on_software'
This works perfectly by giving me the warehouse that the user has access to and its values but, now, i wanted to invert the result such as in a pivot table so that if the user was Peter, this would be the result:
type--|-----A----
XX----|-----123123
YY----|-----3423423
ZZ----|-----3423345
And if the user was kim:
type--|-----B---------|-----C
XX----|-----123123-|---234324
YY----|-----423423-|---245435
ZZ----|-----423345-|---456233
Is there a way to do this with only select statements, without views or PS?

Dynamic Table Joining Based on Another Table Column Value?

I'm trying to figure out if there is a simple way to dynamically load a 2nd table based on the column value of the first table with mysql
Servers (Table 1):
ID | Game | Title
Servers_1 (Table 2, option 1):
server_id (links to servers.id) | game_version | players | plugins
Servers_2 (Table 2, option 2):
server_id (links to servers.id) | game_version | players | mods | game_map
Servers_etc. (Table 2, option etc.)
Trying to figure out how to do something like
left_join servers_[servers.game] on servers.id = servers_[servers.game].server_id
So it would grab the value of servers.game and use that to finish the table name. If this is not possible, then is a case statement possible such as:
Left_Join
if ( servers.game == 1 ) 'servers_1'
elseif ( servers.game == 2 ) 'servers_2'
elseif ( servers.game == 3 ) 'servers_3'
One option would be to LEFT JOIN each of the tables and use a CASE statement to return the appropriate data.
Something like this should help get you started:
SELECT S.Id, S.Game, S.Title,
CASE S.Game
WHEN 1 THEN S1.game_version
WHEN 2 THEN S2.game_version
END game_version,
...
FROM Servers S
LEFT JOIN Servers_1 S1 ON S.id = S1.Server_Id AND S.Game = 1
LEFT JOIN Servers_2 S2 ON S.id = S2.Server_Id AND S.Game = 2
Instead of using CASE, you could probably just use COALESCE as each Id/Game should be unique and only 1 wouldn't be NULL:
SELECT COALESCE(S1.game_version,S2.game_version,...) game_version
If there is no way the same server id can be in multiple tables, then you can leave the AND S.Game... out of the LEFT JOINs as it wouldn't longer be needed. Depends on your unique keys.
Alternatively, you could use Dynamic SQL.

MySQL - What's wrong with the query?

I am trying to query a database to find the following.
If a customer searches for a hotel in a city between dates A and B, find and return the hotels in which rooms are free between the two dates.
There will be more than one room in each room type (i.e. 5 Rooms in type A, 10 rooms in Type B, etc.) and we have to query the database to find only those hotels in which there is at least one room free in at least one type.
This is my table structure:
**Structure for table 'reservations'**
reservation_id
hotel_id
room_id
customer_id
payment_id
no_of_rooms
check_in_date
check_out_date
reservation_date
**Structure for table 'hotels'**
hotel_id
hotel_name
hotel_description
hotel_address
hotel_location
hotel_country
hotel_city
hotel_type
hotel_stars
hotel_image
hotel_deleted
**Structure for table 'rooms'**
room_id
hotel_id
room_name
max_persons
total_rooms
room_price
room_image
agent_commision
room_facilities
service_tax
vat
city_tax
room_description
room_deleted
And this is my query:
$city_search = '15';
$check_in_date = '29-03-2010';
$check_out_date = '31-03-2010';
$dateFormat_check_in = "DATE_FORMAT('$reservations.check_in_date','%d-%m-%Y')";
$dateFormat_check_out = "DATE_FORMAT('$reservations.check_out_date','%d-%m-%Y')";
$dateCheck = "$dateFormat_check_in >= '$check_in_date' AND $dateFormat_check_out <= '$check_out_date'";
$query = "SELECT $rooms.room_id,
$rooms.room_name,
$rooms.max_persons,
$rooms.room_price,
$hotels.hotel_id,
$hotels.hotel_name,
$hotels.hotel_stars,
$hotels.hotel_type
FROM $hotels,$rooms,$reservations
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_id = $rooms.hotel_id
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot
FROM $reservations
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'";
The number of rooms already reserved in each room type in each hotel will be stored in the reservations table.
The thing is the query doesn't return any result at all. Even though it should if I calculate it myself manually.
I tried running the sub-query alone and I don't get any result. And I have lost quite some amount of hair trying to de-bug this query from yesterday. What's wrong with this? Or is there a better way to do what I mentioned above?
Edit: Code edited to remove a bug. Thanks to Mark Byers.
Sample Data in reservation table
1 1 1 2 1 3 2010-03-29 2010-03-31 2010-03-17
2 1 2 3 3 8 2010-03-29 2010-03-31 2010-03-18
5 1 1 5 5 4 2010-03-29 2010-03-31 2010-03-12
The sub-query should return
Room ID : 1 Rooms Booked : 7
Room ID : 2 Rooms Booked : 8
But it does not return any value at all.... If i remove the dateCheck condition it returns
Room ID : 2 Rooms Booked : 8
Your problem is here:
$rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations,$rooms
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'"
You are doing a subtraction total_rooms - (tot, id) where the first operand is a scalar value and the second is a table with two columns. Remove one of the columns in the result set and make sure you only return only one row.
You also should use the JOIN keyword to make joins instead of separating the tables with commas. That way you won't forget to add the join condition.
You probably want something along these lines:
SELECT column1, column2, etc...
FROM $hotels
JOIN $rooms
ON $hotels.hotel_id = $rooms.hotel_id
JOIN (
SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations
JOIN $rooms
ON ??? /* Aren't you missing something here? */
WHERE $dateCheck
GROUP BY $reservations.room_id
) AS T1
ON T1.id = room_id
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - T1.tot > '0'